1 个稳定版本
1.0.0 | 2024 年 5 月 2 日 |
---|
#15 在 #fixture
66 每月下载量
用于 tested-fixture
7KB
111 行
tested-fixture
用于从测试创建设置项的属性宏
描述
有时一系列测试是渐进的或递增的;也就是说一个测试建立在另一个测试之上。一个多阶段测试可能对每个步骤都有复杂的设置和验证过程,但如果有清晰的阶段界限(test_1
验证阶段 1,test_2
验证阶段 2 等。)。当阶段需要共享数据时(即 test_2
想从 test_1
停止的地方开始)就会出现问题。
常见的建议是复制所有设置代码到所有测试中,或者将测试组合成一个大的测试。然而,如果设置成本高昂,前者会显著减慢测试速度,如果设置过程更改,还会带来重大的测试维护成本。后者可能会产生大型且难以维护的测试函数,并且无法解决跨多个文件依赖的问题(即测试 Foo
完整设置过程的单元测试难以与测试 Bar
设置过程的单元测试结合;这个“组合”测试应该放在 Foo
还是 Bar
附近?如果测试需要访问内部结构以验证断言呢?)。
此 crate 通过允许测试返回一个可用于后续测试的设置项来提供一种替代方法。测试可以通过使用单个属性宏 tested_fixture
来选择加入此功能。
用法
当编写类似以下代码的测试时
struct Foo {
// ...
}
struct State {
// ...
}
impl Foo {
fn step_1() -> Self {
Foo {
// Complicated setup...
}
}
fn step_2(&self) -> State {
State {
// Complicated execution...
}
}
fn step_3(&self, v: &State) {
// Complicated execution...
}
}
重复的测试设置可能看起来像这样
#[test]
fn step_1() {
let foo = Foo::step_1();
// Complicated assertions verify step 1...
}
#[test]
fn step_2() {
let foo = Foo::step_1();
// (Some?) Complicated assertions verify step 1...
foo.step_2();
// Complicated assertions verify step 2...
}
#[test]
fn step_3() {
let foo = Foo::step_1();
// (Some?) Complicated assertions verify step 1...
let state = foo.step_2();
// (Some?) Complicated assertions verify step 2...
foo.step_3(&state);
// Complicated assertions verify step 3...
}
如您所见,有很多步骤,这很容易变得难以控制。通过切换到使用 tested_fixture
属性而不是常规的 test
来清理它很简单。
// Save the fixture in a static variable called `STEP_1`
#[tested_fixture::tested_fixture(STEP_1)]
fn step_1() -> Foo {
let foo = Foo::step_1();
// Complicated assertions verify step 1...
foo
}
#[tested_fixture::tested_fixture(STEP_2_STATE)]
fn step_2() -> State {
let state = STEP_1.step_2();
// Complicated assertions verify step 2...
state
}
#[test]
fn step_3() {
STEP_1.step_3(&STEP_2_STATE);
// Complicated assertions verify step 3...
}
请注意,当仅运行 step_2
时,在首次访问时会初始化 STEP_1
。由于测试的顺序没有保证,即使两个测试都运行,这也可能发生。但由于结果被缓存,step_1
测试应该仍然成功(或失败),无论它是否首先运行。
高级用法
tested_fixture
属性支持属性和标识符前的可见性级别前缀,以及一个可选的 : type
后缀。此可选后缀可用于返回 Result
的测试,以指定仅应捕获 Ok
返回值。例如
#[tested_fixture::tested_fixture(
/// Doc comment on the `STEP_1` global variable
pub(crate) STEP_1: Foo
)]
fn step_1() -> Result<Foo, &'static str> {
// ...
}
限制
普通的 #[test]
函数能够返回任何实现了 std::process::Termination
的类型,包括无限嵌套的 Result
。虽然这个crate支持返回嵌套的 Result
包装,但它仅支持到固定深度。此外,它不支持返回任何其他除了 Result
之外的 Termination
实现。
与所有与测试相关的全局状态一样,建议测试不要修改状态,因为这会增加由于执行顺序或时间变化而导致测试不稳定的风险。幸运的是,这是默认行为,因为这个crate定义的所有.fixture都只能通过不可变引用访问。
目前这个crate不支持异步测试。
许可证
许可证下
- MIT许可证(《LICENSE》或https://opensource.org/licenses/MIT》)
依赖关系
~1.4–2MB
~40K SLoC