9.2 使用cargo test进行测试
在 Rust 项目中,cargo test 是运行测试的核心命令。它不仅能够执行你编写的测试代码,还提供了丰富的选项来控制测试的行为,是 Rust 开发流程中不可或缺的一部分。
9.2.1 基本用法
当你创建一个新的库项目(例如 cargo new my_library --lib)时,Cargo 会自动生成一个测试模块和示例测试函数。在项目根目录下运行 cargo test,Cargo 会编译项目中的所有测试代码(包括 #[test] 标记的函数和文档测试),然后执行它们并报告结果。
$ cargo test
Compiling my_library v0.1.0 (/path/to/my_library)
Finished test [unoptimized + debuginfo] target(s) in 0.31s
Running unittests src/lib.rs (target/debug/deps/my_library-...)
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
输出结果会清晰地显示:
- 编译状态。
- 测试运行的位置(通常是
unittests)。 - 每个测试的名称和结果(
ok表示通过,FAILED表示失败)。 - 最终的统计摘要:通过数、失败数、忽略数、性能测试数和过滤数。
9.2.2 常用命令行选项
cargo test 支持多种选项,帮助你精确控制测试的执行。
运行特定的测试:可以通过测试名称来过滤要运行的测试。
cargo test会运行所有名称中包含指定字符串的测试。# 运行所有名称中包含 "test_add" 的测试 cargo test test_add显示测试输出:默认情况下,通过测试的
println!输出会被捕获并隐藏。使用-- --nocapture可以显示所有测试的标准输出。cargo test -- --nocapture--用于分隔 Cargo 的参数和测试二进制文件的参数。只运行被忽略的测试:使用
-- --ignored可以运行所有标记为#[ignore]的测试。cargo test -- --ignored并行执行测试:默认情况下,测试会使用多个线程并行执行。你可以使用
-- --test-threads=<count>来控制线程数量,例如设置为1来串行执行,这在测试共享资源时很有用。# 使用单线程运行所有测试 cargo test -- --test-threads=1运行文档测试:Rust 支持在文档注释中编写测试代码(
///或//!)。使用cargo test --doc可以只运行这些文档测试。cargo test --doc
9.2.3 测试的组织结构
测试代码通常放在两个地方:
单元测试:与源代码放在同一个文件中,但位于一个标记为
#[cfg(test)]的模块内。这个条件编译属性确保测试代码只在运行cargo test时被编译,而不会包含在最终的发布版本中。// src/lib.rs pub fn add_two(a: i32) -> i32 { a + 2 } #[cfg(test)] mod tests { use super::*; #[test] fn it_adds_two() { assert_eq!(4, add_two(2)); } }集成测试:通常放在项目根目录下的
tests目录中。每个.rs文件都会被编译成一个独立的 crate。集成测试只能调用库的公开 API(即pub标记的函数和方法)。// tests/integration_test.rs use my_library; #[test] fn test_add_two_integration() { assert_eq!(4, my_library::add_two(2)); }
9.2.4 测试属性
除了 #[test],还有其他有用的属性:
#[ignore]:标记一个测试为“忽略”,在默认运行cargo test时会被跳过。常用于标记耗时较长或暂时失败的测试。#[should_panic]:用于测试代码是否按预期触发panic!。可以指定expected参数来匹配 panic 消息。#[test] #[should_panic(expected = "attempt to divide by zero")] fn test_divide_by_zero() { let _ = 1 / 0; }
9.2.5 断言宏
Rust 标准库提供了几个用于测试的断言宏:
assert!(expression):如果表达式为false,则测试失败。assert_eq!(left, right):如果左右两个值不相等,则测试失败。要求两个值实现PartialEq和Debugtrait。assert_ne!(left, right):如果左右两个值相等,则测试失败。
这些宏都支持可选的格式化参数,用于在失败时提供自定义的错误消息。
#[test]
fn test_with_message() {
let result = 2 + 2;
assert_eq!(result, 5, "2 + 2 的结果应该是 5,但实际结果是 {}", result);
}
9.2.6 工作区中的测试
如果你的项目是一个包含多个 crate 的工作区(workspace),在根目录运行 cargo test --workspace 或 cargo test -p <crate_name> 可以分别测试所有 crate 或指定的 crate。
通过熟练掌握 cargo test 的各种用法,你可以构建一个健壮、可靠的测试体系,从而更有信心地进行代码重构和功能迭代。
