Pea*_*nut 27 testing unit-testing rust
我想编写依赖于参数的测试用例.我应该为每个参数执行我的测试用例,我想看看每个参数是成功还是失败.
我习惯在Java中写这样的东西:
@RunWith(Parameterized.class)
public class FibonacciTest {
@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{ 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }
});
}
private int fInput;
private int fExpected;
public FibonacciTest(int input, int expected) {
fInput= input;
fExpected= expected;
}
@Test
public void test() {
assertEquals(fExpected, Fibonacci.compute(fInput));
}
}
Run Code Online (Sandbox Code Playgroud)
我怎样才能实现与Rust相似的东西?简单的测试用例工作正常,但有些情况下还不够.
#[test]
fn it_works() {
assert!(true);
}
Run Code Online (Sandbox Code Playgroud)
注意:我希望参数尽可能灵活,例如:从文件中读取它们,或者使用某个目录中的所有文件作为输入等.因此,硬编码的宏可能还不够.
Chr*_*gan 33
内置的测试框架不支持这个; 最常用的方法是使用宏为每个案例生成一个测试,如下所示:
macro_rules! fib_tests {
($($name:ident: $value:expr,)*) => {
$(
#[test]
fn $name() {
let (input, expected) = $value;
assert_eq!(expected, fib(input));
}
)*
}
}
fib_tests! {
fib_0: (0, 0),
fib_1: (1, 1),
fib_2: (2, 1),
fib_3: (3, 2),
fib_4: (4, 3),
fib_5: (5, 5),
fib_6: (6, 8),
}
Run Code Online (Sandbox Code Playgroud)
这将产生与名称单独测试fib_0,fib_1,&C.
Mic*_*ico 24
我的rstest箱子模仿pytest语法并提供了很大的灵活性。斐波那契示例可以非常简洁:
use rstest::rstest;
#[rstest]
#[case(0, 0)]
#[case(1, 1)]
#[case(2, 1)]
#[case(3, 2)]
#[case(4, 3)]
#[case(5, 5)]
#[case(6, 8)]
fn fibonacci_test(#[case] input: u32, #[case] expected: u32) {
assert_eq!(expected, fibonacci(input))
}
pub fn fibonacci(input: u32) -> u32 {
match input {
0 => 0,
1 => 1,
n => fibonacci(n - 2) + fibonacci(n - 1)
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
/home/michele/.cargo/bin/cargo test
Compiling fib_test v0.1.0 (file:///home/michele/learning/rust/fib_test)
Finished dev [unoptimized + debuginfo] target(s) in 0.92s
Running target/debug/deps/fib_test-56ca7b46190fda35
running 7 tests
test fibonacci_test::case_1 ... ok
test fibonacci_test::case_2 ... ok
test fibonacci_test::case_3 ... ok
test fibonacci_test::case_5 ... ok
test fibonacci_test::case_6 ... ok
test fibonacci_test::case_4 ... ok
test fibonacci_test::case_7 ... ok
test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Run Code Online (Sandbox Code Playgroud)
每个案例都作为一个单独的测试案例运行。
语法简单整洁,如果需要,您可以使用任何 Rust 表达式作为case参数中的值。
rstest还支持泛型和pytest类似装置。
不要忘记添加rstest到dev-dependenciesin Cargo.toml。
可能不是你问过相当的东西,但通过TestResult::discard与快速检查可以测试使用随机生成的输入子集的功能.
extern crate quickcheck;
use quickcheck::{TestResult, quickcheck};
fn fib(n: u32) -> u32 {
match n {
0 => 0,
1 => 1,
_ => fib(n - 1) + fib(n - 2),
}
}
fn main() {
fn prop(n: u32) -> TestResult {
if n > 6 {
TestResult::discard()
} else {
let x = fib(n);
let y = fib(n + 1);
let z = fib(n + 2);
let ow_is_ow = n != 0 || x == 0;
let one_is_one = n != 1 || x == 1;
TestResult::from_bool(x + y == z && ow_is_ow && one_is_one)
}
}
quickcheck(prop as fn(u32) -> TestResult);
}
Run Code Online (Sandbox Code Playgroud)
我从这个Quickcheck教程中学习了Fibonacci测试.
PS当然,即使没有宏和快速检查,您仍然可以在测试中包含参数."把事情简单化".
#[test]
fn test_fib() {
for &(x, y) in [(0, 0), (1, 1), (2, 1), (3, 2), (4, 3), (5, 5), (6, 8)].iter() {
assert_eq!(fib(x), y);
}
}
Run Code Online (Sandbox Code Playgroud)
无需使用任何额外的包,您可以这样做,因为您可以编写返回 Result 类型的测试
#[cfg(test)]
mod tests {
fn test_add_case(a: i32, b: i32, expected: i32) -> Result<(), String> {
let result = a + b;
if result != expected {
Err(format!(
"{} + {} result: {}, expected: {}",
a, b, result, expected
))
} else {
Ok(())
}
}
#[test]
fn test_add() -> Result<(), String> {
[(2, 2, 4), (1, 4, 5), (1, -1, 0), (4, 2, 0)]
.iter()
.try_for_each(|(a, b, expected)| test_add_case(*a, *b, *expected))?;
Ok(())
}
}
Run Code Online (Sandbox Code Playgroud)
您甚至会收到一条不错的错误消息:
---- tests::test_add stdout ----
Error: "4 + 2 result: 6, expected: 0"
thread 'tests::test_add' panicked at 'assertion failed: `(left == right)`
left: `1`,
right: `0`: the test returned a termination value with a non-zero status code (1) which indicates a failure', /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/test/src/lib.rs:194:5
Run Code Online (Sandbox Code Playgroud)
可以使用构建脚本基于任意复杂的参数和构建时已知的任何信息(包括您可以从文件加载的任何信息)构建测试。
我们告诉 Cargo 构建脚本在哪里:
Cargo.toml
[package]
name = "test"
version = "0.1.0"
build = "build.rs"
Run Code Online (Sandbox Code Playgroud)
在构建脚本中,我们生成测试逻辑并使用环境变量将其放置在文件中OUT_DIR:
构建.rs
fn main() {
let out_dir = std::env::var("OUT_DIR").unwrap();
let destination = std::path::Path::new(&out_dir).join("test.rs");
let mut f = std::fs::File::create(&destination).unwrap();
let params = &["abc", "fooboo"];
for p in params {
use std::io::Write;
write!(
f,
"
#[test]
fn {name}() {{
assert!(true);
}}",
name = p
).unwrap();
}
}
Run Code Online (Sandbox Code Playgroud)
最后,我们在测试目录中创建一个文件,其中包含生成文件的代码。
测试/generated_test.rs
include!(concat!(env!("OUT_DIR"), "/test.rs"));
Run Code Online (Sandbox Code Playgroud)
就是这样。让我们验证测试是否运行:
[package]
name = "test"
version = "0.1.0"
build = "build.rs"
Run Code Online (Sandbox Code Playgroud)
使用https://github.com/frondeus/test-case箱。
例子:
#[test_case("some")]
#[test_case("other")]
fn works_correctly(arg: &str) {
assert!(arg.len() > 0)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3535 次 |
| 最近记录: |