前言#
昨天我们知道了如何选择性测试某些测试元
今天继续往下学
测试组织(Tests Organization)#
今天来说下两个概念,集成测试(integration tests)和单元测试(unit tests)。
单元测试(Unit Test)#
其实我们之前学的全都是单元测试,是直接写在每一个文件(src文件夹下)里的。
还记得之前的例子中使用的#[cfg(test)][3]吗?
这就是在声明一个测试模块,它们不会占用你编译的时间和空间,只有你在开发时执行cargo test时他们才会被转换成binary然后执行,而使用run/build输出的代码中是没有测试相关代码的。
cfg是一个attribute,之前我们见过的attribute还有derive 。
cfg是configuration的缩写。 而test是configuration这个attribute的option也就是选项。
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 4);
}
}大家应该都很熟悉了。
当然,你的测试函数必须注释#[test],不然也是不会执行的。
另外在rust中要测试私有方法[4]等会比其他语言简单些(当然,不包括js:我想怎么用就这么用,什么?闭包里的方法?打扰了)。
我们直接来看下例子
pub fn add_two(a: i32) -> i32 {
internal_adder(a, 2)
}
fn internal_adder(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn internal() {
assert_eq!(4, internal_adder(2, 2));
}
}
由于是在同一个文件中,我们直接super一下就好了。
集成测试(Integration test)#
和单元测试相反,集成测试得放在library之外,也就是说它们调用你的library和这个库被别的project直接引用一样。另外它是全部测试的,也就是说单元测试是对的并不意味着集成测试也是对的,所以集成测试是必不可少的。
我们来创建一个tests的文件夹,和src同级。cargo默认会去这个tests文件夹找测试块。tests文件夹里的每一个test文件都会被编译成单独的crate。
我们再tests文件夹下创建一个名为integration_test.rs的文件,在里面调用lib.rs里的method。
use adder;
#[test]
fn it_adds_two() {
assert_eq!(4, adder::add_two(2));
}
由于每一个test文件都是一个crate,所以引用外部的crate都得使用use将它们导入先(prelude的另说)。
adder是我们的包名字,之前有说过,如果是调用库的话,路径得从包名开始。而且由于lib.rs是默认library文件,所以并不需要adder::lib::add_two这样调用。
另外我们也不需要去注释#[cfg(test)],因为都已经移出来了。

测试正常,然后我把刚才注释掉的unit test代码注释回来,再test一次

可以看到都被执行了。它里面包含了三部分,单元测试、集成测试和文档测试,不过我们的代码里没有文档测试相关的。
有一点需要注意的是,如果其中一种fail了之后,后续的就都不会执行了。比如在单元测试中fail了,那么集成测试中是不会运行的

如果只是想测试某个test文件,我们可以直接在终端输入
cargo test --test integration_test
--test ${filename}另外,如果你有文件是放在tests文件夹里的,但是这里面放的都不是测试用代码,而是一些helper,它们默认也会被当做tests文件编译。
rust官方也是考虑到了这个问题。[6]
我们先在tests文件夹里新建一个common.rs文件,然后搞个setup方法。
pub fn setup() {
// setup code specific to your library's tests would go here
} 
可以看到他也被编译进去了,这不是我们想要的。
为了避免这种情况,我们得把common.rs改成common/mod.rs

这样就避开了。
之前学packages/module/crate的时候有说过,rust查找module的时候的规律,其中有一个就是xxx/mod.rs,比如下面的例子
use adder;
mod common;
#[test]
fn it_adds_two() {
common::setup();
assert_eq!(4, adder::add_two(2));
}
我们用的common这个mod,就是根据tests/common/mod.rs查找规则找到的。
最后说一下如果项目里只有binary crate,不包含library crate,那么你这个项目是不能创建test的。
binary crate的代码意味着只能是binary自己使用,所以它们的代码并不需要test,有需要则自行抽离公共方法放到lib中。这也算是一种好的开发约束吧。
总结#
我们现在学会了如何创建test包括集成测试和单元测试。
这一章是比较轻松的。
最后,如果这篇文章对你有帮助的话,请务必点个赞,谢谢~
参考#
- ^rust-tests-organization https://doc.rust-lang.org/book/ch11-03-test-organization.html#test-organization
- ^rust-unit-test https://doc.rust-lang.org/book/ch11-03-test-organization.html#unit-tests
- ^rust-test-module https://doc.rust-lang.org/book/ch11-03-test-organization.html#the-tests-module-and-cfgtest
- ^rust-test-private-method https://doc.rust-lang.org/book/ch11-03-test-organization.html#testing-private-functions
- ^rust-integration-test https://doc.rust-lang.org/book/ch11-03-test-organization.html#integration-tests
- ^rust-submodule-in-integration-tests https://doc.rust-lang.org/book/ch11-03-test-organization.html#submodules-in-integration-tests
发布于 2022-12-20 22:52・IP 属地广东
