2 个版本
0.1.1 | 2019 年 6 月 23 日 |
---|---|
0.1.0 | 2019 年 6 月 23 日 |
#325 in 测试
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
特性的断言类型。
还有更多的断言可用
- 比较两个值(
Equal
、NotEqual
、Greater
、Less
、GreaterEqual
、LessEqual
) - 测试布尔值(
True
、False
) - 确保一个值包含在向量中(
Contains
) - 由迭代器定义的多个断言(
Multiple
)
您还可以通过实现 Assert
特性来创建自己的断言类型。
许可证
许可协议之一
- Apache许可证,版本2.0,(LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT许可证 (LICENSE-MIT 或 http://opensource.org/licenses/MIT)
由您选择。