【Rust自学】11.1. 编写和运行测试

【Rust自学】11.1. 编写和运行测试
11.1 编写和运行测试11.1.1. 什么是测试在Rust里测试就是一个函数用于验证非测试代码的行为是否符合预期。一个测试函数通常执行三个操作- 准备(Arrange)数据/状态- 运行(Act)被测试的代码- 断言(Assert)结果这三个操作在有些语言里叫3A步骤。11.1.2. 解剖测试函数测试函数本质上仍然是一个函数不同之处在于它必须用test属性(attribute)进行标注。Attribute就是一段Rust代码的元数据。它不会改变被它修饰的代码的逻辑只是对代码进行修饰或者说标注。实际上在 5.2. struct使用例加打印调试信息 中就已经用到过。在函数上加#[test]就可以把函数变为测试函数。11.1.3. 运行测试先不管测试函数内的内容编写完测试函数之后如何运行它呢使用cargo test命令来运行所有测试。这个命令会构建一个测试运行器(test runner)可执行文件。它会逐个运行标注了test的函数并报告它们是否成功。当使用Cargo创建library项目时会生成一个test module里面有一个现成的test函数可以参照它来编写其他测试函数。实际上你可以添加任意数量的test module或test函数。看个例子创建一个名为adder的新库项目$ cargo new adder --lib Creating library adder package note: see more Cargo.toml keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html $ cd adder打开项目lib.rspub fn add(left: usize, right: usize) - usize { left right } #[cfg(test)] mod tests { use super::*; #[test] fn it_works() { let result add(2, 2); assert_eq!(result, 4); } }之所以这是一个测试函数是因为它被#[test]标注了而不是因为它位于test模块中。test模块里也可以包含普通函数。使用cargo test来运行测试$ cargo test Compiling adder v0.1.0 (file:///projects/adder) Finished test profile [unoptimized debuginfo] target(s) in 0.12s Running unittests src/lib.rs (target/debug/deps/adder-302521ba8d0f0bdf) running 1 test test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s Doc-tests adder running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s分析一下这个输出- 首先是编译(Compiling)、完成(Finished)和运行(Running)。- 接下来是running 1 test表示正在执行一个测试。下一行显示这个测试是tests::it_works结果是ok。这个项目只有一个测试但如果有多个测试cargo test会全部运行。- 然后是test result: ok.表示项目中的所有测试都通过了。具体来说1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out表示1个通过、0个失败、0个被忽略、0个基准测试、0个被过滤掉。-Doc-tests adder指的是文档测试的结果。Rust能够编译出现在API文档中的代码这有助于保证文档始终与实际代码保持同步。如果把函数改名输出哪里会变呢pub fn add(left: usize, right: usize) - usize { left right } #[cfg(test)] mod tests { use super::*; #[test] fn exploration() { // 改名为 exploration let result add(2, 2); assert_eq!(result, 4); } }输出$ cargo test Compiling adder v0.1.0 (file:///projects/adder) Finished test profile [unoptimized debuginfo] target(s) in 0.08s Running unittests src/lib.rs (target/debug/deps/adder-302521ba8d0f0bdf) running 1 test test tests::exploration ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s Doc-tests adder running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s可以看到测试名从tests::it_works变成了tests::exploration。11.1.4. 测试失败测试函数一旦触发panic!测试就失败。由于每个测试都在自己的线程中运行主线程会监视这些线程。当主线程看到某个测试因触发panic!而崩溃时那个测试就会被标记为失败。看个例子pub fn add(left: usize, right: usize) - usize { left right } #[cfg(test)] mod tests { use super::*; #[test] fn exploration() { let result add(2, 2); assert_eq!(result, 4); } #[test] fn another() { panic!(Make this test fail); } }这个another函数直接调用了panic!。运行一下看结果$ cargo test Compiling adder v0.1.0 (file:///projects/adder) Finished test profile [unoptimized debuginfo] target(s) in 0.08s Running unittests src/lib.rs (target/debug/deps/adder-302521ba8d0f0bdf) running 2 tests test tests::exploration ... ok test tests::another ... FAILED failures: ---- tests::another stdout ---- thread tests::another (448960) panicked at src/lib.rs:17:9: Make this test fail note: run with RUST_BACKTRACE1 environment variable to display a backtrace failures: tests::another test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s error: test failed, to rerun pass --libtests::another失败了而tests::exploration仍然是ok。失败原因是thread tests::another panicked at src/lib.rs:17:9意思是在src/lib.rs的第17行第9列触发了panic!也就是源代码中写该宏的位置。总结一下test result: FAILED表示整体测试运行失败。更具体地说是1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out。