#单元测试 #单元 #运行器 #aaa #测试运行器 #测试

test4a

提供一些工具以应用“高级”的 Arrange-Act-Assert 测试设计的测试库。

2 个版本

0.1.1 2019 年 6 月 23 日
0.1.0 2019 年 6 月 23 日

#325 in 测试

MIT/Apache

43KB
864

Test4A

用 Rust 编写的测试库,提供了一些工具来应用“高级”的 Arrange-Act-Assert 测试设计。

目录

简介

Arrange-Act-Assert 是一种广泛使用的单元测试设计方式。当应用时,每个用例都可以以以下形式编写

#[test]
fn test_use_case() {
    // Arrange    
    // Act
    // Assert
}

这种技术确保了我们的测试既清晰又界限分明。然而,如果我们想确保一个类型的所有方法都正确工作,我们必须定义很多用例,因此测试代码很快就会膨胀。
Test4A 背后的主要思想是以紧凑和可重用的方式定义用例,以便更有效地编写单元测试。

以下是该库的主要思想

  • 定义测试的另一种方法,以便更易于阅读
  • 更多断言类型
  • 定义自定义断言的简单方法
  • 支持崩溃测试
  • 当测试失败时,对错误进行清晰的描述并提供关于用例的详细信息
  • 与 Rust 和 Cargo 提供的工具的出色集成
  • 不受测试类型限制(一些测试框架要求类型实现 Clone,但 Test4A 不需要任何特质)
  • 不需要任何宏

安装

要在您的 crate 中使用 Test4A,只需在您的 Cargo.toml 中包含以下内容

[dev_dependencies]
test4a = "0.1"

用法

为了清楚地了解如何使用 Test4A,让我们为 usize 类型编写一些单元测试。

第一个用例

我们可以从编写第一个用例开始

#[cfg(test)]
mod tests {
    use test4a::{Equal, Runner};

    struct Expected {
        value: usize,
    }

    #[test]
    fn test_from_0() {
        Runner::arrange(|message| {
            message.set("Value of 0");
            0
        })
        .act(
            |message, value| {
                message.set("Add 1");
                *value += 1;
            },
            || Expected { value: 1 },
        )
        .assert(|message, value, expected| {
            message.set("Value is correct");
            Equal::new(value, expected.value)
        });
    }
}

在这里,我们定义了一个测试,初始化 usize 变量为 0,添加 1,并测试值是否有效为 1。代码组织成 Arrange-Act-Assert 设计,就像我们通常做的那样。

Expect 是您定义的一种类型,用于在 Act 步骤和 Assert 步骤之间传递数据。您可以使用 message 参数为每个步骤定义一个自定义标签。这些标签将在失败的案例中打印出来,以便快速找到哪个用例失败了。

多个用例

在前一节中,我们定义了一个单一用例。然而,我们可以看到编写了大量的代码来定义它。当我们要定义多个用例时,Test4A 就变得有趣了。

首先,让我们为我们的 usize 对象定义一些初始状态

  • x = 0(零)
  • x = 1(非零值)

对于每个初始状态,我们想要测试一些操作

  • x += 0(添加零)
  • x += 1(添加一个非零值)
  • x -= 1(减去一个非零值)

我们可以为每个操作编写一个函数

fn add_0(message: &mut Message, value: &mut usize) {
    message.set("Add 0");
    *value += 0;
}

fn add_1(message: &mut Message, value: &mut usize) {
    message.set("Add 1");
    *value += 1;
}

fn subtract_1(message: &mut Message, value: &mut usize) {
    message.set("Subtract 1");
    *value -= 1;
}

然后,我们可以定义所有想要检查的断言。在这里,我们只想确保执行操作后值是正确的。这里是相应的函数

fn value_expected(
    message: &mut Message,
    value: usize,
    expected: Expected,
) -> Equal<usize> {
    message.set("Value is correct");
    Equal::new(value, expected.value)
}

该函数应返回一个实现 Assert 特性的类型。Equal 是库中包含的这些类型之一。更多信息可以在 断言 部分找到。

现在,我们可以为每个初始状态定义一个运行器,并使用之前定义的函数来确定要执行哪些操作和断言

#[test]
fn test_from_0() {
    Runner::arrange(|message| {
        message.set("Initial value of 0");
        0
    })
    .act(add_0, || Expected { value: 0 })
    .act(add_1, || Expected { value: 1 })
    .act(subtract_1, || Expected { value: 0 }) // This test will fail, see next section
    .assert(value_expected);
}

#[test]
fn test_from_1() {
    Runner::arrange(|message| {
        message.set("Initial value of 1");
        1
    })
    .act(add_0, || Expected { value: 1 })
    .act(add_1, || Expected { value: 2 })
    .act(subtract_1, || Expected { value: 0 })
    .assert(value_expected);
}

所有操作/断言的可能组合将独立执行(为每个案例执行 arrange 步骤)。

您可以在每个运行器中定义任意多的操作和断言。
需要注意的是,在并行执行与 cargo test 时,运行器中的所有用例将顺序执行。

确保代码崩溃

如果您执行上述定义的测试,一个测试将会失败。这发生在我们尝试从 0 减去 1 的时候。在这种情况下,我们并不期望 usize 对象的值,而是代码崩溃。

要定义一个对于给定安排应引发恐慌的操作,您可以使用 act_panic

Runner::arrange(|message| {
    message.set("Initial value of 0");
    0
})
.act(add_0, || Expected { value: 0 })
.act(add_1, || Expected { value: 1 })
.act_panic(PanicWhen::Debug, subtract_1)
.assert(expect_value);

在这里,我们向 Test4A 指示,当代码以调试模式构建时,substract_1 操作才会引发恐慌。
该操作定义的用例立即停止:后续的断言将不会执行。

同样,您可以使用 assert_panic 来断言在测试断言时代码引发恐慌。

断言

在前面的章节中,我们已经看到了 Test4A 定义的断言类型之一:Equal
为了提供更多断言并控制它们,库定义了一个实现 Assert 特性的断言类型。

还有更多的断言可用

  • 比较两个值(EqualNotEqualGreaterLessGreaterEqualLessEqual
  • 测试布尔值(TrueFalse
  • 确保一个值包含在向量中(Contains
  • 由迭代器定义的多个断言(Multiple

您还可以通过实现 Assert 特性来创建自己的断言类型。

许可证

许可协议之一

由您选择。

无运行时依赖