测试 #
单元测试 #
在Rust中,单元测试与被测试的代码存储在同一个源文件中。也就是说,对于任何给定的结构体、函数或方法,其对应的单元测试通常位于同一个源文件中。测试通常位于文件底部附近。
提示 如果太多逻辑被放到了一个源文件中尤其是在您有复杂的测试的情况下。一旦超过1000行代码,我们就需要考虑重构了。
示例某lib.rs
:
1pub fn add<T: std::ops::Add<Output = T>>(a: T, b: T) -> T {
2 a + b
3}
4
5 // tests mod中包含测试,#[cfg(test)] attribute告诉编译器这是的单元测试模块
6#[cfg(test)]
7mod tests {
8 use super::*;
9
10 // #[test] attribute告诉编译器这个函数是一个单元测试
11 #[test]
12 fn test_add() {
13 assert_eq!(add(3, 4), 7);
14 }
15}
运行测试:
1cargo test
测试框架 #
- rstest - 引入了诸如fixture(用于注入测试依赖)、 parametrize(用于多值参数化测试)和async支持等功能。
- proptest - 是一个属性测试框架。它允许测试代码的某些属性是否对任意输入都成立,如果发现失败,会自动找到重现问题的最小测试用例。用来进行随机测试
parameterizedtest-caseassert2
单元测试覆盖率 #
支持单元测试覆盖率显示:
- cargo tarpaulin: 运行测试并分析你的Rust代码并提供代码覆盖率数据
- cargo watch: 每次我们保存文件时,运行
cargo tarpaulin
- coverage gutters: 在VSCode中显示覆盖的代码行
1cargo install cargo-tarpaulin
cargo tarpaulin命令的更多参数详见。
1cargo tarpaulin --out Lcov --output-dir target/tarpaulin
上面的命令在target/tarpaulin目录里生成了lcov.info
文件。
CMD+Shift+P
输入Coverage Gutters: Watch
输入后,会自动发现lcov.info文件,并在项目源码中显示测试覆盖率。
安装cargo-watch:
Cargo Watch监视你的项目的源代码是否有变化,并在变化发生时运行Cargo命令。
1cargo install cargo-watch
1cargo watch -x 'tarpaulin --out Lcov --output-dir target/tarpaulin'
性能优化:
1cargo watch -x 'tarpaulin --out Lcov --output-dir target/tarpaulin' -w src
集成测试 #
https://doc.rust-lang.org/rust-by-example/testing/integration_testing.html
集成测试是从公共接口对单个模块或组进行测试。
在Rust中与单元测试不同,集成测试位于主源代码树之外。Rust将集成测试视为单独的包,它们只能访问公开导出的函数和结构。
单元测试一次只测试一个独立的模块:它们很小,可以测试私有代码。集成测试位于你的 crate 外部,并且像任何其他代码一样只使用其公共接口。它们的目的是测试库的许多部分是否能正确地协同工作。Cargo 会在 src
旁边的 tests
目录中查找集成测试。
文件src/lib.rs
:
1// Define this in a crate called `adder`.
2pub fn add(a: i32, b: i32) -> i32 {
3 a + b
4}
文件tests/integration_test.rs
:
1#[test]
2fn test_add() {
3 assert_eq!(adder::add(3, 2), 5);
4}
执行测试:
1$ cargo test
2running 0 tests
3
4test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
5
6 Running target/debug/deps/integration_test-bcd60824f5fbfe19
7
8running 1 test
9test test_add ... ok
10
11test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
12
13 Doc-tests adder
14
15running 0 tests
16
17test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
tests
目录中的每个Rust源文件都被编译成一个单独的crate。为了在集成测试之间共享一些代码,我们可以创建一个包含公共函数的模块,并在测试中导入和使用它。
文件tests/common/mod.rs
:
1pub fn setup() {
2 // some setup code, like creating required files/directories, starting
3 // servers, etc.
4}
文件tests/integration_test.rs
:
1// importing common module.
2mod common;
3
4#[test]
5fn test_add() {
6 // using common code.
7 common::setup();
8 assert_eq!(adder::add(3, 2), 5);
9}
创建模块为tests/common.rs
也可以工作,但不推荐这样做,因为测试运行器会将该文件视为测试crate并尝试运行其中的测试。
测试框架 #
- assert_cmd 简化CLI的集成测试过程,包括:查找要测试的 crate 的二进制文件;断言程序运行的结果。
- rexpect
文档测试 #
记录Rust项目的主要方式是通过对源代码添加注释。文档注释采用CommonMark Markdown规范编写,并支持其中的代码块。Rust 注重代码的正确性,因此这些代码块会被编译并用作文档测试。
模糊测试(Fuzz testing) #
模糊测试使用随机生成的数据来测试代码,这些数据不一定有效。模糊测试在安全敏感的环境中尤其受欢迎,在这种情况下,希望了解当代码被滥用时会发生什么。