【Rust自学】11.4. 用should_panic检查恐慌

【Rust自学】11.4. 用should_panic检查恐慌
11.4 用should_panic检查恐慌11.4.1. 验证错误处理的情况除了验证代码是否返回正确的值测试还需要验证代码是否如预期处理了错误情况。例如可以编写一个测试来验证代码是否在特定条件下发生恐慌。这类测试需要额外的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有一个类型为i32的字段value。它提供关联函数new用于创建Guess实例但前提是传给new的参数在1到100之间否则就会恐慌。greater_than_100测试函数给new传入大于100的值。这时应该发生恐慌所以给这个测试函数加了should_panic属性也就是写#[should_panic]。测试结果$ cargo test Compiling guessing_game v0.1.0 (file:///projects/guessing_game) Finished test profile [unoptimized debuginfo] target(s) in 0.12s Running unittests src/lib.rs (target/debug/deps/guessing_game-bdc6b9a45c563cc0) running 1 test test tests::greater_than_100 - should panic ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s Doc-tests guessing_game running 0 tests test 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 { 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标记本应恐慌却没有恐慌的测试就会失败$ cargo test Compiling guessing_game v0.1.0 (file:///projects/guessing_game) Finished test profile [unoptimized debuginfo] target(s) in 0.09s Running unittests src/lib.rs (target/debug/deps/guessing_game-bdc6b9a45c563cc0) running 1 test test tests::greater_than_100 - should panic ... FAILED failures: ---- tests::greater_than_100 stdout ---- note: test did not panic as expected at src/lib.rs:21:8 failures: tests::greater_than_100 test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s error: test failed, to rerun pass --lib11.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 test Compiling guessing_game v0.1.0 (file:///projects/guessing_game) Finished test profile [unoptimized debuginfo] target(s) in 0.08s Running unittests src/lib.rs (target/debug/deps/guessing_game-bdc6b9a45c563cc0) running 1 test test tests::greater_than_100 - should panic ... FAILED failures: ---- tests::greater_than_100 stdout ---- thread tests::greater_than_100 (457156) panicked at src/lib.rs:12:13: Guess value must be greater than or equal to 1, got 200. note: run with RUST_BACKTRACE1 environment variable to display a backtrace note: panic did not contain expected string panic 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_100 test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s error: test failed, to rerun pass --lib失败信息表明测试确实发生了恐慌但恐慌消息没有包含期待的字符串less than or equal to 100。在这种情况下我们实际收到的恐慌信息是Guess value must be greater than or equal to 1, got 200.。根据这些信息就足以修复这个bug。