Rust 测试

2022-04-16 language rust

Rust 支持常规的单元测试、集成测试等,甚至还支持文档测试。

单元测试

单元测试需要放到 tests 而且带有 #[cfg(test)] 属性的模块中,测试函数要加上 #[test] 属性。

pub fn add(a: i32, b: i32) -> i32 {
    a + b
}
fn main() {
    println!("Hello, world!");
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_add() {
        assert_eq!(add(1, 2), 3);
    }
}

当函数中出现 panic 时测试就失败了,如下是常用的断言宏:

  • assert!(expression) 当表达式的值是 falsepanic,也可以添加失败时的自定义信息。
  • assert_eq!(left, right)assert_ne!(left, right) 检验左右两边是否相等、不等。

如果某个函数预期出现 panic 可以通过如下方式配置。

#[test]
#[should_panic(expected = "Your panic info")]
fn test_add() {
    assert_eq!(add(1, 2), 3);
}

如果是类似 Result 这种可恢复的错误,那么可以通过如下方式测试。

assert!(some_error().is_err());
assert!(some_error().is_err_and(|e| e.kind() == ErrKind::NotFound));

let e = some_error().unwrap_err();
assert_eq!(e.kind(), ErrKind::NotFound);

然后通过 cargo test 命令执行所有测试用例,或者通过 cargo test test_add 指定某个测试用例,或者通过 cargo test add 匹配所有相关用例。

另外,还可以通过 #[ignore] 标记不执行某个用例,如果要执行则通过 cargo test -- --ignored 执行。

----- 控制并行度
cargo test -- --test-threads=1
----- 显示输出
cargo test -- --show-output
----- 查看所有用例
cargo test -- --list
----- 可以通过 --lib --doc 控制只运行库或者文档测试用例
cargo test --lib --package xxx

上述的 --package 参数指定的是目录下 Cargo.toml 中的 package.name 参数。

Fuzz

关于 Fuzz 测试可以参考 The Fuzzing Book 中的介绍,而 Rust 相关的更多内容可以参考 Rust Fuzz Book 中的介绍。

----- 方式安装升级
cargo install cargo-fuzz
cargo install --force cargo-fuzz

----- 查看帮助信息
cargo fuzz --help

----- 新建工程,一般会生成fuzz目录以及一个简单示例
cargo fuzz init
----- 也可以手动添加新的示例
cargo fuzz add <your-fuzz-name>

此时会生成对应的示例代码,可以根据项目的需要进行修改,包括用例的名称、依赖等。

----- 查看支持的测试列表
cargo fuzz list
----- 开始测试
cargo fuzz run <your-fuzz-name>

如果出现报错,会同时输出包括的数组内容,以及 Reproduce with 以及 Minimize test case with 两条命令,可以手动执行进行验证,可以有效缩短异常的场景。

libfuzzer

这也是默认的,通常会有如下的输出。

#19644289 REDUCE cov: 383 ft: 2112 corp: 639/89Kb lim: 4096 exec/s: 8031 rss: 650Mb L: 1080/3078 MS: 1 EraseBytes-

可以解读为:

  • #19644289 已经测试过的数据次数。
  • cov 当前已经覆盖的代码块。
  • ft 尝试覆盖信号个数。
  • corp 当前随机序列的入口个数,以及其所占用的内存大小。
  • lim 当前最大为 65535 字节,也就输入的长度。
  • exec/s 迭代速度,每秒多少次。
  • rss 当前内存消耗。
  • L 当前输入实际所占字节。

其它

建议使用 cargo-nextest 查看测试结果,要比原生更加方便使用,执行 cargo nextest run 即可。

文档测试

通常在文档中会维护一些示例代码,为了保证其正确性,可以通过 rustdoc 命令进行测试。

覆盖率

建议使用 tarpaulin 工具,相比 cargo-llvm-cov 来说功能要更丰富,可以通过 cargo install cargo-tarpaulin 安装,然后直接执行 cargo tarpaulin 命令即可。

可以通过 -o html 指定输出 Web 页面。