Rust 学习笔记 20:项目实战二:构建 grep 命令行工具 (minigrep)

Rust 学习笔记 20:项目实战二:minigrep “UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity.” – Dennis Ritchie 到目前为止,我们已经学习了 Rust 的大部分核心特性。现在,让我们把它们串起来,复刻一个经典的命令行工具:grep。 我们的目标是创建一个 minigrep,它接受一个查询字符串和一个文件名,然后打印出文件中包含查询字符串的行。 1. 需求分析 用法: 1$ cargo run -- searchstring example-filename.txt 功能点: 读取命令行参数。 读取文件内容。 筛选包含关键词的行。 错误处理(用户没传参数?文件不存在?)。 关注点分离:main.rs 负责处理参数和系统调用,lib.rs 负责核心逻辑。 TDD:测试驱动开发。 环境变量:支持 IGNORE_CASE=1 进行大小写不敏感搜索。 2. 核心代码演进 我们将代码分为 main.rs 和 lib.rs。 2.1 参数解析与配置 在 src/lib.rs 中定义 Config 结构体: 1use std::env; 2 3pub struct Config { 4 pub query: String, 5 pub file_path: String, 6 pub ignore_case: bool, 7} 8 9impl Config { 10 pub fn build(mut args: impl Iterator<Item = String>) -> Result<Config, &'static str> { 11 args.next(); // 也就是程序名,通常忽略 12 13 let query = match args.next() { 14 Some(arg) => arg, 15 None => return Err("Didn't get a query string"), 16 }; 17 18 let file_path = match args.next() { 19 Some(arg) => arg, 20 None => return Err("Didn't get a file path"), 21 }; 22 23 let ignore_case = env::var("IGNORE_CASE").is_ok(); 24 25 Ok(Config { 26 query, 27 file_path, 28 ignore_case, 29 }) 30 } 31} 注意这里使用了 impl Iterator,这样我们可以直接消费 env::args(),更加高效。 ...

2025-11-04 · 2 min · 344 words · 老墨

模糊测试入门 (Fuzzing)

大家好,我是极客老墨。 单元测试只能测试你想到的情况。空字符串、负数、超长输入,这些边界情况很容易遗漏。模糊测试能自动生成大量随机输入,帮你发现那些没想到的 Bug。 这篇就聊聊 Go 的模糊测试,看看它是怎么帮我们提升代码质量的。 什么是模糊测试 模糊测试(Fuzzing)是一种自动化测试技术,通过生成随机输入来发现程序的异常。 核心思想 1// 传统单元测试:测试已知输入 2func TestAdd(t *testing.T) { 3 if Add(2, 3) != 5 { 4 t.Error("2 + 3 should be 5") 5 } 6 if Add(0, 0) != 0 { 7 t.Error("0 + 0 should be 0") 8 } 9} 10 11// 模糊测试:测试大量随机输入 12func FuzzAdd(f *testing.F) { 13 f.Fuzz(func(t *testing.T, a, b int) { 14 result := Add(a, b) 15 // 检查属性而不是具体值 16 if a > 0 && b > 0 && result <= 0 { 17 t.Errorf("Add(%d, %d) = %d, overflow?", a, b, result) 18 } 19 }) 20} 区别: ...

2025-08-20 · 8 min · 1548 words · 老墨

Rust 学习笔记 17:自动化测试 (Automated Testing)

Rust 学习笔记 17:自动化测试 (Automated Testing) “Program testing can be a very effective way to show the presence of bugs, but it is hopelessly inadequate for showing their absence.” – Edsger W. Dijkstra 在 Go 中,我们创建 _test.go 文件,写 func TestXxx(t *testing.T)。 在 Rust 中,测试是一等公民。你不需要特殊的目录结构(单元测试),也不需要额外的测试框架。 1. 单元测试 (Unit Tests) 按照惯例,Rust 的单元测试直接写在源代码文件中,通常放在底部的 tests 模块里。 1// src/lib.rs 2 3fn add(a: i32, b: i32) -> i32 { 4 a + b 5} 6 7#[cfg(test)] 8mod tests { 9 use super::*; // 引入父模块的所有内容 10 11 #[test] 12 fn it_works() { 13 assert_eq!(add(2, 2), 4); 14 } 15} #[cfg(test)]:告诉编译器,只有在运行 cargo test 时才编译这个模块。生成的二进制文件不会包含这些测试代码,零空间开销。 #[test]:标记一个函数为测试函数。 assert_eq! / assert!:断言宏。 2. 测试私有函数 Rust 的单元测试允许测试私有函数!这是很多语言做不到的(Java 需要反射或放宽可见性)。 因为测试模块就定义在源码文件内部,且是子模块,它天然拥有访问父模块私有内容的权限。 ...

2025-06-10 · 2 min · 226 words · 老墨

[GoLang避坑实战-14] 写得爽,跑得快:表格驱动测试的工程级避坑实战

大家好,我是极客老墨! 刚转 Go 的时候,我还在找"Go 版的 JUnit 在哪"。结果发现,Go 根本不需要第三方测试框架,go test 命令 + testing 包就够了。 写测试不只是为了完成 KPI,更是为了**“让自己晚上能睡个好觉”**。这篇我们不仅聊基础,更要聊聊在大厂工程实践中,如何写出既稳健又专业的测试。 Go中的测试,不是"一等公民",是"超等公民"。Go 编译器自带 go test 工具,标准库提供 testing 包,写测试简单到爆。 1. 单元测试:从入门到专业 Go 的测试文件规则很简单:以 _test.go 结尾,函数名以 Test 开头。 1.1 基础写法 1func TestAdd(t *testing.T) { 2 if got := Add(1, 2); got != 3 { 3 t.Errorf("Add(1, 2) = %d; want 3", got) 4 } 5} 跑一下: 1$ go test -v 2=== RUN TestAdd 3--- PASS: TestAdd (0.00s) 4PASS 5ok example.com/math 0.392s 就这么简单。不需要装任何库,不需要配置文件。 ...

2025-02-19 · 3 min · 491 words · 老墨

Python教程28:单元测试基础

Python教程28:单元测试基础 “测试不是万能的,但没有测试是万万不能的。” 代码写完了但不敢重构?担心修改一处就影响全局?单元测试能给你信心。今天我们学习Python的unittest模块,掌握自动化测试的基础。 1. 什么是单元测试 测试的重要性 为什么需要测试: 验证代码的正确性 防止回归(修改代码导致原有功能失效) 提高代码质量 便于重构(有测试保障) 作为文档(测试展示如何使用函数) 单元测试(Unit Test): 测试最小可测试单元(函数、方法、类) 独立运行,互不影响 快速执行 自动化 测试示例 待测试的代码: 1# calculator.py 2def add(a, b): 3 """加法""" 4 return a + b 5 6def divide(a, b): 7 """除法""" 8 if b == 0: 9 raise ValueError("除数不能为零") 10 return a / b 手动测试(不推荐): 1# 手动测试,繁琐且不可重复 2print(add(2, 3)) # 应该是5 3print(divide(10, 2)) # 应该是5 4# 每次修改代码都要手动运行... 自动化测试(推荐): 1# test_calculator.py 2import unittest 3from calculator import add, divide 4 5class TestCalculator(unittest.TestCase): 6 """ 7 测试用例类 8 - 继承unittest.TestCase 9 - 测试方法以test_开头 10 - 使用断言验证结果 11 """ 12 13 def test_add(self): 14 """测试加法""" 15 self.assertEqual(add(2, 3), 5) 16 self.assertEqual(add(-1, 1), 0) 17 18 def test_divide(self): 19 """测试除法""" 20 self.assertEqual(divide(10, 2), 5) 21 22 with self.assertRaises(ValueError): 23 divide(10, 0) 24 25if __name__ == "__main__": 26 unittest.main() 运行测试: ...

2025-02-07 · 5 min · 1059 words · 老墨