基本写法

在 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! 等。

  1. pub fn mylib() -> u32 {
  2. 1
  3. }
  4. #[cfg(test)]
  5. mod tests {
  6. use super::*;
  7. #[test]
  8. fn it_works() {
  9. assert_eq!(mylib(), 1);
  10. }
  11. }

在单测中可以通过是否调用 panic!或者返回 Result<T, E> 的方式来告诉测试是否执行通过

  1. #[cfg(test)]
  2. mod tests {
  3. use super::*;
  4. #[test]
  5. fn test_panic() {
  6. if 2 + 2 == 4 {
  7. panic!("123")
  8. }
  9. }
  10. #[test]
  11. fn test_result() -> Result<(), String> {
  12. if 2 + 2 > 4 {
  13. Ok(())
  14. } else {
  15. Err(String::from("111"))
  16. }
  17. }
  18. }

单测中可以加上 #[should_panic]的注解,用于验证抛出异常的流程是否符合预期。

  1. #[cfg(test)]
  2. mod tests {
  3. use super::*;
  4. #[test]
  5. #[should_panic(expected = "should throw err")]
  6. fn it_should_panic() {
  7. panic!("should throw err");
  8. }
  9. }

可以加上 #[ignore] 的注解,用于忽略某些单测的执行

  1. #[cfg(test)]
  2. mod tests {
  3. use super::*;
  4. #[test]
  5. #[ignore]
  6. fn it_should_panic() {
  7. panic!("should throw err");
  8. }
  9. }

执行单测

直接执行以下指令即可。

  1. $ cargo test

跑单测的时候有不少参数可以带来不同的执行效果,详情可以直接执行 cargo test --helpcargo test -- --help 看到不同的执行参数( 两个指令展示的是不同的参数配置 )。

这里也列一下常用的一些用法:

显示 println! 信息

跑单测默认会把日志打印给忽略掉,如果需要输出就加上个 --show-output 的 args 即可。

  1. $ cargo test -- --show-output

筛选执行的测试

类似于 mocha 里的 --grep='xxx' ,在 Rust 中直接在 test 后加上筛选的表达式即可。比如下面的就会筛选名字包含 works的测试函数执行。

  1. $ cargo test works

如果需要带一些 args ,就

  1. $ cargo test -- --show-ouput works

独立测试文件

如果想把单测独立到单个文件中 Rust 也是支持的,可以在项目的根目录下建个 tests 目录。然后新建个 mylib_test.rs 文件

  1. // tests/mylib_test.rs
  2. use mylib; // 这个是你的 crate lib 名称
  3. #[test]
  4. fn it_works_in_single() {
  5. assert_eq!(mylib::mylib(), 1)
  6. }

然后执行 cargo test --tests 就可以执行上面的单测。如果执行 cargo test --tests 就会执行 tests 目录下的所有单测以及写在 lib 中的单测。

在 tests 目录中也可以申明一些通用的 module 供单测使用,写法跟在 src 中一致,比如新建一个 tests/util.rs 的文件

  1. // tests/util.rs
  2. pub fn get_one() -> u32 {
  3. 1
  4. }

tests/mylib_test.rs 中就可以。

  1. use mylib;
  2. mod util;
  3. #[test]
  4. fn it_works_in_single() {
  5. assert_eq!(mylib::mylib(), util::get_one())
  6. }

如何测试 binary

Rust 的建议是,将核心逻辑写到 src/lib.rs 中,在 binary ( 比如 main.rs )中引入 lib 中的函数调用,然后就测 lib 即可。