Rust数据驱动-参数化测试
需求
假如有以下测试用例,同样的逻辑,我们需要测试多组数据。
mod tests {
#[test]
fn test_add() {
let a = 1;
let b = 2;
assert_eq!(a + b, 3);
}
}
一般情况下我们不在用例中使用for循环(即subtests子测试模式)来验证多组数据。
mod tests {
#[test]
fn test_add() {
for a in [1, 2, 3] {
assert_eq!(a + a, 2 * a);
}
}
}
因为这样只是一个用例,而不是一组数据一个用例,同时前面的数据出错也会导致后面的数据测试不到。
使用三方包-实现数据驱动测试
Rust中想要进行参数化测试,可以使用三方包,或者自己编写宏,常用的数据驱动三方包如下:
- test-case: 支持通过标记进行参数化
- rtest:支持参数化标记和自定义fixture依赖
- test-generator: 支持基于文件的数据驱动
- datatesgt: 支持基于稳定的数据驱动和通过yaml生成多个结构体数据
以test-case为例
mod tests {
use test_case::test_case;
#[test_case(1, 1, 2; "1+1应等于2")]
#[test_case(2, 3, 5; "2+3应等于5")]
#[test_case(0, 0, 0; "0+0应等于0")]
fn test_add(a: i32, b: i32, excepted: i32) {
assert_eq!(a + b, excepted);
}
}
测试结果如图:
也可以在项目中使用cargo test执行所有测试,结果如下:
running 3 tests
test add_test::tests::test_add::_0_0应等于0 ... ok
test add_test::tests::test_add::_1_1应等于2 ... ok
test add_test::tests::test_add::_2_3应等于5 ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
自定义宏-实现数据驱动测试
当然,也可以自己编写宏实现,例如:
macro_rules! make_testcase {
($test_func_name:ident, $a:expr, $b:expr, $excepted:expr) => {
#[test]
fn $test_func_name() {
assert_eq!($a + $b, $excepted);
}
}
}
mod tests {
make_testcase!(test_add_0, 1, 2, 3);
make_testcase!(test_add_1, 2, 3, 5);
make_testcase!(test_add_2, 0, 0, 0);
}
多轮随机数据测试
上面的数据驱动都是基于明确已有的多组数据进行测试的,如果想要使用多轮随机数据进行测试,可通过 test-case + seq + 自定义宏
来实现,例如:
macro_rules! make_testcases {
($count:expr) => {
mod tests {
use rand::Rng;
use seq_macro::seq;
use test_case::test_case;
seq!(N in 0..$count {
#(#[test_case(N)])*
fn test_add(index: usize) {
let mut rng = rand::thread_rng();
let a = rng.gen_range(0..10);
assert_eq!(a + a, 2 * a)
}
});
}
};
}
mod tests {
make_testcases!(3);
}
依赖Cargo.toml
[dependencies]
test-case = "*"
seq-macro = "*"
rand = "*"
执行效果如下: