喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)
11.4.1. 验证错误处理的情况
测试函数出了验证代码的返回值是否正确,还需要验证代码是否如预期的去处理了发生错误的情况。比如说可以编写一个测试来验证代码是否在特定情况下发生了panic!
。
这种测试需要为函数额外增加should_panic
属性。使用它标记的函数,如果在函数内发生了恐慌,则代表通过测试;反之就失败。
看个例子:
pub struct Guess {value: i32,
}impl Guess {pub fn new(value: i32) -> Guess {if value < 1 || value > 100 {panic!("Guess value must be between 1 and 100, got {value}.");}Guess { value }}
}#[cfg(test)]
mod tests {use super::*;#[test]#[should_panic]fn greater_than_100() {Guess::new(200);}
}
- 结构体
Guess
有一个存储u32
类型数据的字段value
,它有一个关联函数new
用于创建一个Guess
实例,但前提是传进new
的参数大于1小于100,否则就要恐慌。 greater_than_100
这个测试函数测试给new
函数传入大于100的值,这时候应该发生恐慌,所以为这个测试函数添加了一个should_panic
的attribute(属性),也就是写#[should_panic]
。
测试结果:
$ cargo testCompiling guessing_game v0.1.0 (file:///projects/guessing_game)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.58sRunning unittests src/lib.rs (target/debug/deps/guessing_game-57d70c3acb738f4d)running 1 test
test tests::greater_than_100 - should panic ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sDoc-tests guessing_gamerunning 0 teststest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
下面来人为引入bug,把new
函数里的value > 100
的判断去掉:
pub struct Guess {value: i32,
}impl Guess {pub fn new(value: i32) -> Guess {if value < 1 || value > 100 {panic!("Guess value must be between 1 and 100, got {value}.");}Guess { value }}
}#[cfg(test)]
mod tests {use super::*;#[test]#[should_panic]fn greater_than_100() {Guess::new(200);}
}
这时候测试函数中的Guess::new(200);
就不会恐慌,但是因为它添加了should_panic
这个attribute,所以本应该恐慌的函数没有恐慌就会导致测试失败:
$ cargo testCompiling guessing_game v0.1.0 (file:///projects/guessing_game)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.62sRunning unittests src/lib.rs (target/debug/deps/guessing_game-57d70c3acb738f4d)running 1 test
test tests::greater_than_100 - should panic ... FAILEDfailures:---- tests::greater_than_100 stdout ----
note: test did not panic as expectedfailures:tests::greater_than_100test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00serror: test failed, to rerun pass `--lib`
11.4.2. 让should_panic
更精确
有的时候使用should_panic
进行的测试会有点含糊不清,因为它仅仅能够说明被检查的代码是否发生了恐慌,即使这个恐慌和程序员预期的恐慌不一样。
为了使测试更精确,可以为should_panic
添加一个可选的expected
参数。这样程序就会检查失败消息中是否包含所指定的文字。
看个例子:
pub struct Guess {value: i32,
}impl Guess {pub fn new(value: i32) -> Guess {if value < 1 {panic!("Guess value must be greater than or equal to 1, got {value}.");} else if value > 100 {panic!("Guess value must be less than or equal to 100, got {value}.");}Guess { value }}
}#[cfg(test)]
mod tests {use super::*;#[test]#[should_panic(expected = "less than or equal to 100")]fn greater_than_100() {Guess::new(200);}
}
- 在刚才的结构体上稍微进行了修改,把
new
函数里value < 1
和value > 100
的情况分开写了两个不同的恐慌信息。 - 给
should_panic
属性添加了expected
参数,=
后面跟的就是期待的报错信息。只有测试函数恐慌并且恐慌信息包括期待的报错信息才算测试成功,否则就算失败。
这个程序肯定能成功。
一样的套路,我们来手动引入错误,比如我们把new
函数里小于1和大于100的恐慌信息交换一下:
pub struct Guess {value: i32,
}impl Guess {pub fn new(value: i32) -> Guess {if value < 1 {panic!("Guess value must be less than or equal to 100, got {value}.");} else if value > 100 {panic!("Guess value must be greater than or equal to 1, got {value}.");}Guess { value }}
}#[cfg(test)]
mod tests {use super::*;#[test]#[should_panic(expected = "less than or equal to 100")]fn greater_than_100() {Guess::new(200);}
}
测试结果:
$ cargo testCompiling guessing_game v0.1.0 (file:///projects/guessing_game)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.66sRunning unittests src/lib.rs (target/debug/deps/guessing_game-57d70c3acb738f4d)running 1 test
test tests::greater_than_100 - should panic ... FAILEDfailures:---- tests::greater_than_100 stdout ----
thread 'tests::greater_than_100' panicked at src/lib.rs:12:13:
Guess value must be greater than or equal to 1, got 200.
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: panic did not contain expected stringpanic message: `"Guess value must be greater than or equal to 1, got 200."`,expected substring: `"less than or equal to 100"`failures:tests::greater_than_100test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00serror: test failed, to rerun pass `--lib`
失败消息表明此测试确实发生了恐慌,但是恐慌消息不包含less than or equal to 100
预期字符串。在这种情况下我们确实收到的恐慌信息是 Guess value must be greater than or equal to 1, got 200.
。根据这个就可以纠错。