基本写法
在 Rust 中写单元测试也是很重要的一环,在前面的 Package, Crate 的学习中,其实就已经见过单测了,因为执行 cargo new xxx --lib 生成出来的项目的 src/lib.rs里是默认有单测模板的了。
只要是带了 #[cfg(test)]注解的 module ,都会认为是单测 module ,Rust 跑单测时会自动去单测 module 中找带了 #[test] 注解的函数来执行( 类似于 JS mocha 里的 it('xxx') ),Rust 也提供了不少用于单测的宏方法,比如 assert_eq! assert! 等。
pub fn mylib() -> u32 {1}#[cfg(test)]mod tests {use super::*;#[test]fn it_works() {assert_eq!(mylib(), 1);}}
在单测中可以通过是否调用 panic!或者返回 Result<T, E> 的方式来告诉测试是否执行通过
#[cfg(test)]mod tests {use super::*;#[test]fn test_panic() {if 2 + 2 == 4 {panic!("123")}}#[test]fn test_result() -> Result<(), String> {if 2 + 2 > 4 {Ok(())} else {Err(String::from("111"))}}}
单测中可以加上 #[should_panic]的注解,用于验证抛出异常的流程是否符合预期。
#[cfg(test)]mod tests {use super::*;#[test]#[should_panic(expected = "should throw err")]fn it_should_panic() {panic!("should throw err");}}
可以加上 #[ignore] 的注解,用于忽略某些单测的执行
#[cfg(test)]mod tests {use super::*;#[test]#[ignore]fn it_should_panic() {panic!("should throw err");}}
执行单测
直接执行以下指令即可。
$ cargo test
跑单测的时候有不少参数可以带来不同的执行效果,详情可以直接执行 cargo test --help 及 cargo test -- --help 看到不同的执行参数( 两个指令展示的是不同的参数配置 )。
这里也列一下常用的一些用法:
显示 println! 信息
跑单测默认会把日志打印给忽略掉,如果需要输出就加上个 --show-output 的 args 即可。
$ cargo test -- --show-output
筛选执行的测试
类似于 mocha 里的 --grep='xxx' ,在 Rust 中直接在 test 后加上筛选的表达式即可。比如下面的就会筛选名字包含 works的测试函数执行。
$ cargo test works
如果需要带一些 args ,就
$ cargo test -- --show-ouput works
独立测试文件
如果想把单测独立到单个文件中 Rust 也是支持的,可以在项目的根目录下建个 tests 目录。然后新建个 mylib_test.rs 文件
// tests/mylib_test.rsuse mylib; // 这个是你的 crate lib 名称#[test]fn it_works_in_single() {assert_eq!(mylib::mylib(), 1)}
然后执行 cargo test --tests 就可以执行上面的单测。如果执行 cargo test --tests 就会执行 tests 目录下的所有单测以及写在 lib 中的单测。
在 tests 目录中也可以申明一些通用的 module 供单测使用,写法跟在 src 中一致,比如新建一个 tests/util.rs 的文件
// tests/util.rspub fn get_one() -> u32 {1}
在 tests/mylib_test.rs 中就可以。
use mylib;mod util;#[test]fn it_works_in_single() {assert_eq!(mylib::mylib(), util::get_one())}
如何测试 binary
Rust 的建议是,将核心逻辑写到 src/lib.rs 中,在 binary ( 比如 main.rs )中引入 lib 中的函数调用,然后就测 lib 即可。
