测试的组织结构¶
一、测试的分类¶
Rust对测试的分类:
1.1 单元测试¶
测试范围比较小,同时比较专注;一次对一个模块进行隔离的测试;可以测试private接口。
1.2 集成测试¶
完全位于代码库之外,和其他外部代码一样使用你的代码;集成测试可以访问public接口;可能在每个测试中使用到多个模块。
二、单元测试与集成测试的区别¶
单元测试的目的是将一小段代码单独隔离出来,从而迅速地确定这段代码的功能是否符合预期。我们通常把单元测试和被测试代码都放在src
目录下的同一个文件中,同时约定每个源代码文件都要建立一个test
模块放放测试函数,并使用#[cfg(test)]
来标注测试模块。使用#[cfg(test)]
标注之后,那么只有在运行cargo test
命令的时候,测试模块的内容才会被编译并且运行,运行cargo build
则不会。
集成测试在不同的目录中,它不需要使用#[cfg(test)]
进行标注。
说到这里,我们说一下cfg
,实际上是配置的英文单词configuration的缩写,使用cfg
标注的含义是:告诉rust下面条目只有在指定配置选项下才被包含。如:配置选项test
,由rust提供,用来编译和运行测试,只有使用cargo test
才会编译代码,包括模块中的helper函数和#[test]
标注的函数。
三、测试私有函数¶
Rust允许测试私有函数,如下示例代码
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 it_works() {
assert_eq(4, internal_adder(2, 2));
}
}
四、集成测试¶
4.1 集成测试概述¶
在rust里,集成测试完全位于被测试库的外部。集成测试调用库的方式,和其他代码调用库的方式是一样的。同时也意味着,集成测试纸能调用被测试库对外开放的API。集成测试的目的是:测试被测试库的多个部分是否能正确的一起工作。
能够正常工作的代码代码,他们集成在一起运行时,也可能会发生各种问题,所以集成测试的覆盖率很重要的指标。
4.2 测试过程¶
为了创建集成测试,我们需要创建一个tests
目录,这个目录和src
目录时并列的,这个目录也比较特殊,cargo
会自动在这里目录下寻找测试文件。我们可以在tests
目录下创建任意多的测试文件,而该目录下的每个测试文件都是单独的一个crate
。
在执行测试后的输出结果中,每个集成测试文件都会有一个单独的区域,同时每个测试函数都会有一个单独的行。通常在执行集成测试的时候,我们都会有选择地执行。
在测试文件中,需要将被测试测试库导入,每个测试文件无需标注#[cfg(test)]
,因为tests
目录会被cargo特殊对待。在执行cargo test
时,tests
目录下的文件将会被编译。
4.3 运行指定的集成测试¶
运行一个特定的集成测试:cargo test 函数名
运行某个测试文件内的所有测试:cargo test --test 文件名
4.4 集成测试中的自模块¶
tests目录下每个文件会被编译成单独的crate
,这些文件不会共享行为(与src下的文件规则不同)。如果我们想创建一个helper函数,并且在多个测试文件中使用它,我们可以在tests
目录下创建一个空目录,目录名可以叫common
,并把helper函数所在的文件放在该目录中。
rust在测试的过程中,不会把tests
目录下的子目录的文件当作测试文件,该目录只是一个普通的模块而已,现在里面的函数将可以应用于不同的集成测试文件中。如下示例的集成测试代码
// adder为项目名,代表把项目中的所有模块导入到测试文件中
use adder;
// 使用tests目录下的common模块,common模块对应common目录
mod common;
#[test]
fn it_adds_two() {
// 调用common模块下的函数
common::setup();
// 调用项目中的函数
assert_eq!(4, adder::add_two(2));
}
4.5 针对binary crate的集成测试¶
如果项目时binary crate,只含有src/main.rs
没有src/lib.rs
,这时候不能在tests
目录下创建集成测试,集成测试也无法把main.rs
的函数导入到作用域。因为只有library crate才能暴露函数给其他crate使用,而binary crate意味着要独立运行。
rust项目通常把逻辑都放在src/lib.rs
里,而在src/main.rs
只有简单的调用,包含少量的胶水代码。这样在集成测试的时候,就可以把项目视为library,通过使用use
关键字来访问项目中核心的逻辑代码。当核心的逻辑代码没问题了,通常核心功能也没有问题。