编写测试
Rust 提供了强大的内置测试功能支持,使用非常方便。
Rust 使用 #[test]
属性来定义测试函数。这些函数通过该属性被标识出来,并在测试运行时被执行。
测试文件通常以被测试的模块命名,并添加 tests
后缀。例如,如果有一个名为 my_module
的模块,则相应的测试文件将是 my_module_tests.rs
。
测试函数以 test_
前缀命名,后跟一个描述性的名称,表示正在测试什么。函数名称建议使用蛇形命名(snake_case)。
在测试函数中,使用 assert!
宏及其相关宏(如 assert_eq!
和 assert_ne!
)进行断言。断言有助于验证实际结果是否与预期结果相符。
tests/lib_tests.rs:
use tempfile::tempdir;
use lr_grustep::{grep, grep_count, grep_recursive, GrepOptions, MatchItem, MatchResult};
#[test]
fn test_grep() {
let pattern = "fn grep";
let file_content = "This is a test line with fn grep in it.";
let temp_dir = tempdir().expect("Failed to create temporary directory");
let file_path = temp_dir.path().join("test_file.txt");
std::fs::write(&file_path, file_content).expect("Failed to write to temporary file");
let options = GrepOptions {
ignore_case: false,
invert_match: false,
};
let result = grep(pattern, &file_path, &options).unwrap();
let matched_lines = result.get(file_path.to_string_lossy().as_ref()).unwrap();
assert_eq!(matched_lines.len(), 1);
// 检查匹配行的内容
assert_eq!(matched_lines[0].line, file_content.trim());
}
#[test]
fn test_grep_count() {
let mut result = MatchResult::new();
let item = MatchItem {
line_number: 1,
line: String::from("Test line"),
};
result.insert(String::from("test_file.txt"), vec![item]);
let count = grep_count(&result);
assert_eq!(count, 1);
}
#[test]
fn test_grep_recursive() {
let pattern = "TODO";
let temp_dir = tempdir().expect("Failed to create temporary directory");
let nested_dir = temp_dir.path().join("nested");
std::fs::create_dir(&nested_dir).expect("Failed to create nested directory");
let file_content = "TODO: Implement this feature.";
let file_path = temp_dir.path().join("test_file.txt");
let nested_file_path = nested_dir.join("nested_file.txt");
std::fs::write(&file_path, file_content).expect("Failed to write to temporary file");
std::fs::write(&nested_file_path, file_content).expect("Failed to write to nested file");
let options = GrepOptions {
ignore_case: false,
invert_match: false,
};
let result = grep_recursive(pattern, temp_dir.path(), &options).unwrap();
let matched_lines = result.get(file_path.to_string_lossy().as_ref()).unwrap();
assert_eq!(matched_lines.len(), 1);
// 检查匹配行的内容
assert_eq!(matched_lines[0].line, file_content.trim());
// 检查嵌套文件的内容
let nested_matched_lines = result
.get(nested_file_path.to_string_lossy().as_ref())
.unwrap();
assert_eq!(nested_matched_lines.len(), 1);
assert_eq!(nested_matched_lines[0].line, file_content.trim());
}
使用 cargo test
命令运行测试:
cargo test
应该会得到如下测试结果:
Running tests/lib_tests.rs (target/debug/deps/lib_tests-a90b7c416c14752c)
running 3 tests
test test_grep_count ... ok
test test_grep ... ok
test test_grep_recursive ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
如果有错误,你将会看到详细的错误消息,例如:
Running tests/lib_tests.rs (target/debug/deps/lib_tests-a90b7c416c14752c)
running 3 tests
test test_grep_count ... ok
test test_grep ... FAILED
test test_grep_recursive ... ok
failures:
---- test_grep stdout ----
thread 'test_grep' panicked at tests/lib_tests.rs:21:5:
assertion `left == right` failed
left: 0
right: 1
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
test_grep
test result: FAILED. 2 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
error: test failed, to rerun pass `--test lib_tests`
然后,你可以根据此错误消息修复代码逻辑。