写点什么

5 分钟速读之 Rust 权威指南(二十)

用户头像
码生笔谈
关注
发布于: 2021 年 06 月 10 日
5分钟速读之Rust权威指南(二十)

编写测试

在前端开发的时候,要做单元测试的时候,一般使用使用第三方 jest 库,但是在 rust 开发时,rust 已经帮开发者内置了可测试功能

如何编写测试

不管在任何语言中的测试,都不外乎以下三个步骤:


  1. 准备所需的数据或状态。

  2. 调用需要测试的代码。

  3. 断言运行结果与我们所期望的一致。

测试函数的构成

将 #[test]添加到关键字 fn 的上一行便可以将函数转变为测试函数,然后使用 cargo test 命令来运行测试:


#[test]fn it_works() {  assert_eq!(2 + 2, 4);}
复制代码


在测试中如果出现 panic!会导致测试失败:


#[test]fn another() {  panic!("出错了")}
复制代码


assert!检查结果是否为 true:


#[test]fn is_true() {  let is_eq = 2 > 1;  assert!(is_eq);}
复制代码


assert_eq!检查两个数据是否相同:


#[test]fn is_eq() {  // assert_eq!和assert_ne!宏分别使用了==和!=运算符来进行判断,  // 并在断言失败时使用调试输出格式{:?}将参数值打印出来。  // 这意味着它们的参数必须同时实现PartialEq和Debug这两个trait。  #[derive(Debug, PartialEq)]  struct Rect {    width: u32,    height: u32,  }  let rect1 = Rect {    width: 150,    height: 100,  };  let rect2 = Rect { ..rect1 };  assert_eq!(rect1, rect2);}
复制代码


assert_ne!检查两个数据是否不相同:


#[test]fn is_ne() {  fn add(a: i32, b: i32) -> i32 {    a + b  }  assert_ne!(add(1, 2), 4)}
复制代码


添加自定义的错误提示信息:


#[test]fn custom_error() {  let a = 1;  let b = 2;    // 断言函数在必要的参数之后的所有参数都将传递给format!宏,用于打印  assert!(a > b, "{}应该大于{}", a, b);  assert_eq!(a, a, "{}应该等于", a);  assert_ne!(a, b, "{}应该不等于{}", a, b);}
复制代码


在函数上标记 should_panic 属性来断言应该触发异常:


#[test]#[should_panic]fn should_error() {  panic!("应该会出错")}
复制代码


确认抛出的异常是预期的,而不是其他位置的异常:


#[test]#[should_panic(expected = "小于")]fn should_error() {  let a = 1;  let b = 2;  if a > b {    panic!("a大于b")  } else {    panic!("a小于b") // expected中的`小于`在这个panic!中的文字是匹配的  }}
复制代码


使用 Result<T, E>编写测试,这种测试方式可以用来代替 assert 系列的测试方式,函数返回 Ok 时表示测试通过:


#[test]fn use_result() -> Result<(), String> {  let a = 1;  let b = 1;  if a == b {    Result::Ok(()) // Ok的参数需要是空元组  } else {    Result::Err(format!("{} != {}", a, b))  }}
复制代码

控制测试的运行方式

运行测试的参数:


cargo test --help
复制代码


控制测试运行方式,通过--来分隔命令参数:


cargo test -- --help
复制代码


cargo 默认开启并行测试,用于减少测试时间,这就要为多个测试之前不能彼此先后依赖,可以用参数控制具体的线程数:


cargo test -- --test-threads=1
复制代码


在测试通过时,我们无法看到代码中的 println!等标注输出,因为会被 Rust 捕获,使用参数来控制 Rust 不进行捕获标注输出:


cargo test -- --nocapture
复制代码


可以只运行部分测试用例来减少测试时间,例如测试所有匹配字符串is_的测试用例:


cargo test is_
复制代码


运行单个测试:


cargo test it_works
复制代码


注意:不能运行多个测试:


cargo test it_works is_eq
复制代码


通过显式指定来忽略某些测试:


#[test]#[ignore]fn should_ignore() {  panic!("这个错误不会被抛出,因为should_ignore测试不会被运行")}
复制代码


如果想要只运行这些被忽略的测试:


cargo test -- --ignored
复制代码

测试组织结构

单元测试

单元测试一般和业务代码都写在同一文件中,只是通过新建一个测试模块来标识:


pub fn add(a: i32, b: i32) -> i32 {  a + b}
// 标记为测试的模块将会在cargo build后移除// 另外,我们不需要对集成测试标注#[cfg(test)],因为集成测试本身就放置在独立的目录中,rust自然清楚build的时候不进行处理。// cfg: configuration,这里的意思是只有在test时才会被处理#[cfg(test)]mod testaaa { use super::add; #[test] pub fn test_add() { assert_eq!(add(1, 2), 3) }}
复制代码

集成测试

集成测试是完全位于 src 目录之外的 tests 文件夹中:


mkdir tests
复制代码


测试一个外部包 adder:


use adder::add_one;#[test]fn test_add() {  assert_eq!(add_one(1), 2)}
复制代码


测试(包含单元测试、集成测试、文档测试) cargo test:


cargo test
复制代码


只运行某个集成测试:


cargo test --test [集成测试文件名]
复制代码


集成测试公共函数需要放置在 tests/common/mod.rs 文件中,否则放置在其他位置也都将被 rust 识别成集成测试用例:


mod common; // 引用使用公共包#[test]fn test_add() {  // 使用公共包中的setup函数  common::setup();  assert_eq!(add_one(1), 2)}
复制代码


发布于: 2021 年 06 月 10 日阅读数: 11
用户头像

码生笔谈

关注

欢迎关注「码生笔谈」公众号 2018.09.09 加入

前端、Rust干货分享,一起成为更好的Javascripter & Rustacean

评论

发布
暂无评论
5分钟速读之Rust权威指南(二十)