rust开源库test_case参数化测试
在Rust测试生态中,
test-case 是最受欢迎的参数化测试(Parameterized Testing)开源库之一。它通过过程宏(Procedural Macros)极大地简化了“同一套逻辑、多组输入输出”的测试编写。1. 核心作用
在没有该库时,如果你想测试多个输入,通常需要写多个
#[test] 函数或者在函数内部写 for 循环(一旦循环中某项失败,后续测试就不会执行)。使用
test-case 后,你可以通过属性宏直接定义多组用例,且每一组用例都会作为一个独立的测试点在测试報告中显示。2. 基础用法示例
use test_case::test_case;
#[test_case(2, 2 => 4; "基础加法")]
#[test_case(1, 2 => 3; "加法验证")]
#[test_case(-1, 1 => 0; "负数测试")]
fn test_addition(a: i32, b: i32) -> i32 {
a + b
}
- 语法解析:
#[test_case(参数1, 参数2 => 期望返回值; "用例名称")] - 上述语法也可写作不带=>,但校验逻辑写在函数体内:#[test_case(输入, 期望值; "描述")]
- 运行效果:执行
cargo test时,你会看到 3 个独立的测试结果。
3. 高级特性
test-case 支持更复杂的断言和异步测试:A. 复杂的匹配(Matches)
不仅可以对比返回值,还可以断言结果是否符合特定的模式:
#[test_case( 10 => matches Ok(_) )]
#[test_case( -1 => matches Err(MyError::InvalidInput) )]
fn check_input(val: i32) -> Result<(), MyError> {
// 逻辑...
}
B. 异步测试支持
完美配合
tokio 等运行时:#[test_case( "https://rust-lang.org" => 200 )]
#[tokio::test]
async fn test_url_status(url: &str) -> u16 {
let resp = reqwest::get(url).await.unwrap();
resp.status().as_u16()
}
C. 内缀关键词 (Infix Keywords)
支持
it 关键字进行更语义化的断言,例如 it contains, it starts_with 等。4. 为什么推荐使用它?
- 代码整洁度:将测试数据与测试逻辑分离,避免了大量重复的样板代码。
- 调试友好:由于每个 case 都是独立的,当其中一个失败时,你可以清晰地看到是哪组输入出了问题,而不会中断其他 case。
- 兼容性强:它生成的代码本质上依然是标准的
#[test],可以无缝配合 IDE 的测试按钮和cargo-nextest等高级测试运行器。
5. 如何安装
在你的
Cargo.toml 中添加:[dev-dependencies]
test-case = "~3.3.1" # >= 3.3.1, < 3.4.0,请检查最新的版本
总结: 如果你正在编写解析器、算术库或任何需要大量边缘情况验证的代码,
test-case 是必不可少的工具。6. 示例
生成测试Demo:
$ cargo new test_case_eg
目录结构如下:
.
├── Cargo.toml
└── src
├── lib.rs
├── main.rs
└── tct
├── mod.rs
└── tc.rs
编写测试用例tc.rs
#[cfg(test)] mod tests { use test_case::test_case; #[test_case(2, 2 => 4; "基础加法")] #[test_case(1, 2 => 3; "加法验证")] #[test_case(-1, 1 => 0; "负数测试")] fn test_addition(a: i32, b: i32) -> i32 { a + b } }
编写mod.rs
mod tc;
编写lib.rs
pub mod tct;
编写Cargo.toml
[package] name = "test_case_eg" version = "0.1.0" edition = "2024" [dependencies] test-case = "~3.3.1"
验证:
$ cargo test --offline
浙公网安备 33010602011771号