总结了下 rust 写测试案例和测试时近期遇到的一些初步的用法,为以后的使用减少一些疑惑
每个源文件都可以写测试案例,这样案例和源码在一起,方便边测边开发调试的情况。写测试案例的格式也很简单,只要在源文件中加入以下内容:
#[cfg(test)]
mod tests {
#[test]
pub fn screen_test() {
}
}
简单总结就是:
mod
,给 mod
增加注解 #[cfg(test)]
表示这个 mod
只在测试时执行。#[test]
注解的函数就是一个测试案例。没了,就这么多,当然你也可以把源码和测试案例分开放,这是我个人的喜好, 一般情况下我们可以通过 IDE 或编辑器的集成功能来运行和调试测试案例。
注意这里的 run 和 debug 根据我的经验都是 debug 模式运行的,差别只是在于一个进断点,一个不进。 因为我之前有写过循环次数比较多的案例,点 run test 跑了好久,但是用下面的方法,很快就完成了。
可能大部分初学者都会知道,命令行执行测试案例是用 cargo test
。但是这还是没有优化过的程序,
如果想让案例全速执行,你需要加一个参数:
cargo test --release
那么在这个基础上,如果我想执行某个测试案例呢,可能有人会说是这样:
cargo test --release tests::screen_test
也对,也不对,对于我们这个例子是没错,但是如果你有这样几个测试案例:
#[cfg(test)]
mod tests {
#[test]
pub fn screen_test() {}
#[test]
pub fn screen_test1() {}
#[test]
pub fn screen_test2() {}
}
这几个案例都会执行,因为 cargo 会在所有源文件中寻找所有匹配的案例,
如果我们只想运行 screen_test
,cargo
提供了一个参数 —exact
,
这个参数用起来也很讲究,需要放在 — 后面:
cargo test --release tests::screen_test -- --exact
很奇怪对不对,熟悉一点朋友可能会知道这个 — 的用意,它是区分 cargo
和编译后程序的参数,
换句话说, —
前的参数是 cargo
的,后面是 test
的,
我们一般用这种办法向命令行程序传递参数,不过测试案例也可以放后面传,这样在我看来会舒服一点:
cargo test --release -- tests::screen_test --exact
但是我们直接用的话,很可能会发现案例并没有执行:
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.00s
Running unittests src/main.rs (target/release/deps/rich3kit-8cbea6fb2e1f2f7b)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.00s
Running tests/test.rs (target/release/deps/test-e28c8f1f83a0899d)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.00s
Doc-tests rich3kit
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
一堆 0,仰仗 exact
这个参数,test
干脆不干活了,不过简单观察一下,我们可能就能推测出,
这是因为它没有找到这个案例,原因自然是因为我们没有在 cargo test
的命令中体现出源文件的路径,
我们需要这么写:
cargo test --release -- cmd::screen_cmd::tests::screen_test --exact
Finished release [optimized] target(s) in 0.31s
Running unittests src/lib.rs (target/release/deps/rich3kit-9b4b0afca785b931)
running 1 test
test cmd::screen_cmd::tests::screen_test ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in 0.00s
Running unittests src/main.rs (target/release/deps/rich3kit-8cbea6fb2e1f2f7b)
running 1 test
test cmd::screen_cmd::tests::screen_test ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in 0.00s
Running tests/test.rs (target/release/deps/test-e28c8f1f83a0899d)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.00s
Doc-tests rich3kit
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
这下对了,不过我有种这个测试跑了两次的感觉,我们核实一下,修改下我们的案例:
static I: AtomicU32 = AtomicU32::new(0);
#[test]
pub fn screen_test() {
let i = I.fetch_add(1, Ordering::SeqCst) + 1;
assert_eq!(1, i);
}
如果跑了两次会有一次失败,我们再试试看:
cargo test --release -- cmd::screen_cmd::tests::screen_test --exact
Finished release [optimized] target(s) in 0.30s
Running unittests src/lib.rs (target/release/deps/rich3kit-9b4b0afca785b931)
running 1 test
test cmd::screen_cmd::tests::screen_test ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in 0.00s
Running unittests src/main.rs (target/release/deps/rich3kit-8cbea6fb2e1f2f7b)
running 1 test
test cmd::screen_cmd::tests::screen_test ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in 0.00s
Running tests/test.rs (target/release/deps/test-e28c8f1f83a0899d)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.00s
Doc-tests rich3kit
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
看来虽然显示像是跑了两次,但是实际上还是一次,事实上呢其实是分别跑了三次,
一次是为 lib.rs
跑的,一次是为 main.rs
跑的,还有一次为 test.rs
,
但是只有前两个有对应到我们的测试案例,这个和代码结构有关就不再展开了,
不过我们的案例是确定每次只跑了一遍没错。
原以为只是一个简单的总结,方便后续查找,没想到越展开越多了,简单总结一下:
每个源文件都可以写案例,mod
前加 #[cfg(test)]
注解
每个加 #[test]
注解的函数都是测试案例
执行一个具体案例的范例:
cargo test --release -- cmd::screen_cmd::tests::screen_test --exact