俗话说:“测试写得好,奖金少不了。”
有经验的开发人员通常会通过单元测试来保证代码基本逻辑的正确性。如果你是一名新手开发者,并且还没体会到单元测试的好处,那么建议你先读一下我之前的一篇文章。
写单元测试一般需要三个步骤:
准备测试用例,测试用例要能覆盖尽可能多的代码
执行需要测试的代码
判断结果,是否是你希望得到的结果
了解了这些以后,我们就来看看在Rust中应该怎么写单元测试。
首先我们建立一个library项目
$ cargo new adder --lib Created library `adder` project然后在src/lib.rs文件中开始写测试代码
#[cfg(test)] mod tests { #[test] fn it_works() { assert_eq!(2 + 2, 4); } }此时在命令行运行cargo test就会得到测试结果
可以看到,结果显示,Rust运行了一项测试并且测试通过。后面的Doc-tests我们先放下,以后再聊。
当然,这并不是我们常见的测试,在日常开发中,我们通常是先写我们的业务代码然后再对各个函数进行单元测试,最后还会对某个模块进行集成测试。那么我们就来模拟一下日常开发过程中应该如何来写测试。
单元测试我们仍然是用上面的项目,先来在src/lib.rs中写一段“业务代码”
pub fn add_two(a: i32) -> i32 { internal_adder(a, 2) } fn internal_adder(a: i32, b: i32) -> i32 { a + b }这是一段非常简单的代码,对外暴露的函数只是一个加2的功能,内部调用了一个两数相加的函数。现在我们就对这个内部函数做一个单元测试。
#[cfg(test)] mod tests { use super::*; #[test] fn internal() { assert_eq!(4, internal_adder(2, 2)); } }在测试模块中,如果想要使用我们业务代码中的函数,就需要通过use super::*;将其引入可用范围。接着,还是执行cargo test,测试结果与刚才类似。
测了半天全是通过的没什么意思,单元测试真正的作用是要发现代码中的问题,所以我们来尝试一个错误的试一下。假设我们希望2+2等于5。
这里我们的assert_eq!左右不相等,引起了线程恐慌,因此导致测试失败。结果中给出了失败的原因,引起失败的位置,并且有一句提示:note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. 我们按照这个提示,设置变量RUST_BACKTRACE=1,此时再执行cargo test。
Rust就会将错误栈打印出来,根据结果提示,这并不是完整的错误栈,我们还可以将RUST_BACKTRACE设置为full来查看更加详细的信息。这里我就不做演示了。
集成测试接下来我们再演示一下集成测试。我们通常将集成测试单独放到一个目录中,在lib.rs文件中,rust识别测试mod的名称是tests,同样的,我们在src下创建tests目录。tests目录下就是我们的所有集成测试代码。
如图,integration_test是我们测试代码的文件,common目录下的mod.rs文件中是一些集成测试必要的配置。这里我们只是放了一个空的setup函数。
在集成测试中,我们就要像正常他人使用我们的代码时那样来进行测试,首先需要将我们的mod引入到可用范围,当然还需要加上common的mod。
use adder; mod common; #[tests] fn it_adds_two() { common::setup(); assert_eq!(4, adder::add_two(2)); }接着就可以测试我们对外暴露的函数了。
ok,集成测试的方法我们也掌握了。现在来看看一直被我们忽略的Doc-tests吧。
文档测试我们已经知道,Rust中的注释是双斜线//,像我们刚刚写的library代码,如果想要把它发布到crate.io上让别人使用,那么我们就需要增加相应的文档,这里文档的每行都应该是三斜线///开头,而文档中也应该放一些例子供他人参考。
/// Adds two to the number given. /// /// # Examples /// /// ``` /// let arg = 5; /// let answer = adder::add_two(arg); /// /// assert_eq!(7, answer); /// ``` pub fn add_two(a: i32) -> i32 { internal_adder(a, 2) }现在我给add_two函数加上了文档,我们再次执行cargo test命令。
现在我们就明白了,Doc-tests测试就是运行我们文档中的例子。
常用特性到目前为止,我们已经知道了在Rust中如何写测试代码了。接下来我们再来了解几个比较常用的特性。
运行指定的测试代码