rust 测试
test 属性、一些宏和 should_panic 属性
#[cfg(test)]
mod tests {
#[test]
fn exploration() {
assert_eq!(2 + 2, 4);
}
#[test]
fn another() {
panic!("Make this test fail");
}
}
单元测试和集成测试
- 单元测试倾向于更小而更集中,在隔离的环境中一次测试一个模块,或者是测试私有接口
- 集成测试对于你的库来说则完全是外部的。它们与其他外部代码一样,通过相同的方式使用你的代码,只测试公有接口而且每个测试都有可能会测试多个模块
测试的组织结构
单元测试
- 单元测试与他们要测试的代码共同存放在位于 src 目录下相同的文件中。规范是在每个文件中创建包含测试函数的 tests 模块,并使用 cfg(test) 标注模块。
- #[cfg(test)] 注解告诉 rust 只在cargo test 时才编译和运行测试代码,cfg 属性代表 configuration
- Rust 的私有性规则确实允许你测试私有函数,因为在同一个文件中
集成测试
- 集成测试位于tests目录中,与 src 同级,cargo 会将tests下的每一个文件当作单独的 crate 来编译,测试外部库,公共API
- 集成测试位于单独的文件夹中,不需要标识#[cfg(test)]
- cargo test --test 文件名, 只运行 tests 目录中我们指定的文件名中的测试,注意不需要带后缀
- 测试代码中的公共模块,并不需要被测试,为了避免被测试,我们放在mod.rs中,如为了避免 common 出现在测试输出中,我们将创建 tests/common/mod.rs ,而不是创建 tests/common.rs,规则为:tests 目录中的子目录不会被作为单独的 crate 编译或作为一个测试结果部分出现在测试输出中。
单元测试
- assert!宏校验 boolean 值:assert!(true);
- assert_eq! 校验相等:assert_eq!(4, 4);
- assert_ne!校验不相等:assert_eq!(4, 6);
自定义失败信息
- assert!(true, "Greeting did not contain name, value was
{}
", result) - 使用 should_panic 断言异常
#[test] #[should_panic] fn greater_than_100() { panic("出错了") }
- 为了使 should_panic 测试结果更精确,我们可以给 should_panic 属性增加一个可选的 expected 参数
#[test] #[should_panic(expected = "Guess value must be less than or equal to 100")] fn greater_than_100() { Guess::new(200); }
运行测试用例
cargo test
- 运行 cargo test 会有三部分结果:单元测试、集成测试和文档测试
- 选项:选项的一部分可以传递给 cargo test,而另一些则需要传递给生成的测试二进制文件
为了分隔两种类型的参数,首先列出传递给 cargo test 的参数,接着是分隔符 --,再之后是传递给测试二进制文件的参数 cargo test-- --help
获取第二种类型参数的帮助信息
并行或连续的运行测试
- 当运行多个测试时,他们默认使用线程来并行的运行
- 非并行运行:cargo test – --test-threads=1
- 注意输出中不会出现测试通过时打印的内容, 因为被rust测试截取,如需输出,则cargo test – -- nocapture 来开启允许print!
- cargo test 如果没有传任何参数,则默认会运行所有测试
- cargo test test_name 来指定运行某个测试
- cargo test 模糊匹配名称 则会运行所有匹配的测试
- 忽略某些测试
#[test] #[ignore] fn expensive_test() { // code that takes an hour to run } ``
- 只运行忽略的测试
cargo test -- -- ingored
集成测试
只用于测试库,不适用于测试二进制项目,二进制 crate 只意在单独运行