跳转至

测试的组织结构

一、测试的分类

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关键字来访问项目中核心的逻辑代码。当核心的逻辑代码没问题了,通常核心功能也没有问题。