【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 --lib
     Created library `adder` project
$ cd adder

打开项目(lib.rs):

rust 复制代码
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 test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.57s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 1 test
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test 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文档中的这些代码。这可以帮助我们保证文档总会与实际代码同步。

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

rust 复制代码
pub fn add(left: usize, right: usize) -> usize {
    left + right
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn exploration() { //改名为exploration
        let result = add(2, 2);
        assert_eq!(result, 4);
    }
}

输出:

$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.59s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 1 test
test tests::exploration ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test 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!),那个测试就标记为失败了。

看个例子:

rust 复制代码
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 test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.72s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 2 tests
test tests::another ... FAILED
test tests::exploration ... ok

failures:

---- 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 backtrace


failures:
    tests::another

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: 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"

相关推荐
土豆凌凌七2 分钟前
GO:sync.Map
开发语言·后端·golang
重剑无锋102421 分钟前
【《python爬虫入门教程12--重剑无峰168》】
开发语言·爬虫·python
蟹黄堡在逃员工28 分钟前
消息队列MQ(一)
java·后端
小兵张健31 分钟前
记一个 IDEA 关于 Git 的神坑
git·后端·intellij idea
skywalk816332 分钟前
C语言基本知识复习浓缩版:标识符、函数、进制、数据类型
c语言·开发语言
@_@哆啦A梦36 分钟前
Django中自定义模板字符串
后端·python·django
anyup_前端梦工厂40 分钟前
了解 ES6 的变量特性:Var、Let、Const
开发语言·javascript·ecmascript
栗豆包1 小时前
w148基于spring boot的文档管理系统的设计与实现
java·spring boot·后端·spring·tornado
骑着赤兔玩三国1 小时前
Go语言的 的数据封装(Data Encapsulation)核心知识
开发语言·后端·golang
风清云淡_A1 小时前
【linux系统之redis6】redisTemplate的使用方法
redis·后端