当前位置: 首页 > news >正文

【Rust自学】11.1. 编写和运行测试

喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)
请添加图片描述

11.1.1. 什么是测试

在Rust里一个测试就是一个函数,它被用于验证非测试代码的功能是否和预期一致。

在一个测试的函数体里通常执行3个操作:

  • 准备(Arrange)数据/状态
  • 运行(Act)被测试的代码
  • 断言(Assert)结果

这三个操作在有些语言里叫3A操作。

11.1.2. 解剖测试函数

测试函数它的本质就是一个函数,只不过需要使用test属性(英文叫attribute)进行标注。

Attribute就是一段Rust代码的元数据,它不会改变被它修饰的代码的逻辑,它只是对代码进行修饰(或者叫标注)。实际上在 5.2. struct使用例(加打印调试信息)中就用到过,当时用的是

在函数上加#[Test],可以把函数变为测试函数

11.1.3. 运行测试

先不管测试函数内的内容,当我们编写完这个测试函数以后,如何执行测试呢?就使用cargo test这个命令来运行所有的测试。

这个命令会构建一个Test Runner可执行文件,它会逐个运行标注了test的函数,并报告其是否运行成功。

当使用Cargo创建library项目的时候,会生成一个test module,里面有一个现成的test函数,可以参照它来编写其他的测试函数。而实际上,你可以添加任意数量的test module或是test函数。

看个例子:
创建一个名为adder的新库项目:

$ cargo new adder --libCreated library `adder` project
$ cd adder

打开项目(lib.rs):

pub fn add(left: usize, right: usize) -> usize { 
left + right 
}#[cfg(test)]
mod tests {use super::*;#[test]fn it_works() {let result = add(2, 2);assert_eq!(result, 4);}
}

之所以这个函数式测试函数,是因为它上面加了一个test这个Attribute进行修饰,而并不是因为它是一个test模块(test module),因为test模块里也可以有普通的函数。

使用cargo test命令来运行测试:

$ cargo testCompiling adder v0.1.0 (file:///projects/adder)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.57sRunning unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)running 1 test
test tests::it_works ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sDoc-tests adderrunning 0 teststest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

分析一下这个信息:

  • 首先编译(Compiling)、完成编译(Finished)和运行(Running)
  • 后面是"running 1 test",表示正在执行一个测试,往下看一行,可以得到的形式这个测试是tests::it_works。其结果是ok这个项目只有一个测试,如果有多个测试cargo test就会全部跑一遍。
  • 然后是"test result: ok.“,它表示项目里面的所有测试都通过了,具体就是"1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out”,表示1个通过(这里本来就只有1个测试)、0个失败、0个被忽略(函数可被标记为忽略)、0个性能测试、0个被过滤掉的测试。
  • "Doc-tests adder"指的是文档测试的结果,Rust能够编译出现在api文档中的这些代码。这可以帮助我们保证文档总会与实际代码同步。

如果我们把函数改名,输出的结果哪里会变呢:

pub fn add(left: usize, right: usize) -> usize {left + right
}#[cfg(test)]
mod tests {use super::*;#[test]fn exploration() { //改名为explorationlet result = add(2, 2);assert_eq!(result, 4);}
}

输出:

$ cargo testCompiling adder v0.1.0 (file:///projects/adder)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.59sRunning unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)running 1 test
test tests::exploration ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sDoc-tests adderrunning 0 teststest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

可以看到,测试名从tests::it_works变为了tests::exploration

11.1.4. 测试失败

测试函数一旦触发了panic!就表示失败。由于每个测试在运行的时候是在一个独立的线程里,而主线程则会监视这些线程。当主线程看到某个测试挂掉了(触发panic!),那个测试就标记为失败了。

看个例子:

pub fn add(left: usize, right: usize) -> usize {left + right
}#[cfg(test)]
mod tests {use super::*;#[test]fn exploration() {let result = add(2, 2);assert_eq!(result, 4);}#[test]fn another() {panic!("Make this test fail");}
}

这个another函数直接调用了panic!,运行一下看下结果:

$ cargo testCompiling adder v0.1.0 (file:///projects/adder)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.72sRunning unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)running 2 tests
test tests::another ... FAILED
test tests::exploration ... okfailures:---- tests::another stdout ----
thread 'tests::another' panicked at src/lib.rs:17:9:
Make this test fail
note: run with `RUST_BACKTRACE=1` environment variable to display a backtracefailures:tests::anothertest result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00serror: test failed, to rerun pass `--lib`

tests::another失败了,tests::exploration仍然是ok,它失败的原因是"thread ‘tests::another’ panicked at src/lib.rs:17:9"在src下的lib.rs里的17行第9个字符触发了panic!,也就是源代码中写panic!宏的位置。

最后总结了一下:"test result: FAILED"这个测试真题来说是失败了,具体来说:“1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out”


http://www.mrgr.cn/news/83109.html

相关文章:

  • 5 分布式ID
  • js状态模式
  • (已开源-AAAI25) RCTrans:雷达相机融合3D目标检测模型
  • 自动化测试脚本实践:基于 Bash 的模块化测试框架
  • logback日志
  • TCP Analysis Flags 之 TCP Retransmission
  • 如何使用vue引入three.js
  • 人工智能的发展领域之GPU加速计算的应用概述、架构介绍与教学过程
  • 7ZIP 常见使用问题解决办法
  • B+树的原理及实现
  • SpringBoot日常:集成Kafka
  • Python —— 常用的字符串方法
  • JavaSE
  • UnityRenderStreaming使用记录(五)
  • 本地缓存:Guava Cache
  • Ubuntu平台虚拟机软件学习笔记
  • Linux驱动学习之第二个驱动程序(LED点亮关闭驱动程序-分层设计思想,使其能适应不同的板子-驱动程序模块为多个源文件怎么写Makefile)
  • 【深度学习】布匹寻边:抓边误差小于5px【附完整链接】
  • 【vue3封装element-plus的反馈组件el-drawer、el-dialog】
  • docker搭建atlassian-confluence:7.2.0
  • XS5037C一款应用于专业安防摄像机的图像信号处理芯片,支持MIPI和 DVP 接口,内置高性能ISP处理器,支持3D降噪和数字宽动态
  • Onedrive精神分裂怎么办(有变更却不同步)
  • 【Redis源码】 RedisObject结构体
  • 单片机-定时器中断
  • formik 的使用
  • 202305 青少年软件编程等级考试C/C++ 一级真题答案及解析(电子学会)