6 个版本 (3 个重大更新)
0.4.0 | 2023年4月10日 |
---|---|
0.3.0 | 2023年4月7日 |
0.2.2 | 2023年4月3日 |
0.1.1 | 2023年3月27日 |
#354 在 测试
每月下载量 76
15KB
169 行
直观地分享测试用例的部分
什么是子用例?
部分 或 子用例 是单元测试框架(如(很棒)的 C++ 库 Catch2 和 doctest)的酷特性。子用例提供了一种轻松分享代码在测试之间,就像 fixtures 一样,但无需将设置和清理代码移动到测试的主体之外,无需处理面向对象的问题。
它们是如何工作的?子用例允许您将函数执行分支到不同的路径,这些路径将包含您希望它们共有的代码。
让我们来看一个例子。
use subcase::with_subcases;
with_subcases! {
#[test]
fn my_test_case() {
let mut v = vec![1,2,3];
subcase! { ~"single push"
v.push(9);
assert_eq!(v[3], 9);
}
subcase! { ~"clear then push"
v.clear();
assert!(v.is_empty());
for _i in 0..4 { v.push(1); }
}
assert_eq!(v.len(), 4);
assert!(v.capacity() >= 4);
}
}
my_test_case
的主体将执行两次,第一次忽略第二个 subcase!{...}
块,反之亦然。
这还不止!子用例可以嵌套!
use subcase::with_subcases;
with_subcases! {
#[test]
fn my_tremendous_test_case() {
let mut v = vec![1,2,3];
subcase! { ~"single push"
v.push(9);
}
subcase! { ~"clear, push, pop"
v.clear();
v.push(100);
subcase! { ~"push in for loop"
for _i in 0..5 { v.push(1); }
}
subcase! { ~"extend from slice"
v.extend_from_slice(&[4,5,6,7,8]);
}
assert_eq!(v.len(), 6);
v.pop();
v.pop();
}
assert_eq!(v.len(), 4);
}
}
测试函数的主体将执行 3 次:一次为每个叶子子用例(即不包含更多嵌套子用例),而大父级子用例将进入两次。
您可以只编写一个子用例或根本不编写子用例,函数将正常运行。
技术方法和局限性
确实,已经有几个 crate 实现了子用例的概念
subcase crate 与它们各自的区别在于,subcase 只使用轻量级的声明性(即 macro_rules!
)宏,并且没有依赖。此外,with_subcases
宏将所有执行路径都放在一个函数中,而不是生成许多。这使得它相对于上述 crate 来说非常容易。
在 subcase
的方法中,子用例的发现和它们之间的切换在运行时是串行发生的。
这一结果的后果是,测试用例的不同分支不能并行运行。这可能会或可能不会减慢您的测试速度。如果您有大量细粒度的测试用例,您应该没问题。
另一个后果是,通常无法在执行路径之一失败时恢复测试用例。如果它因恐慌而失败,subcase
将报告导致该恐慌的子用例链。
变更日志
您可以在此处阅读变更日志。它遵循通用变更日志样式指南,并使用hallmark工具编写。
许可证
在MIT许可证下授权。