unit-testing - 如何为同一方法命名不同的测试?
问题描述
如何为具有许多不同流程的方法命名测试?
例如,假设我有一个方法 process(),它的行为会根据对象的字段而有所不同:
public void process () {
if (this.someField1 == null) {
doSomethingOne();
else
doSomethingTwo();
if (this.someField2 == null) {
doSomethingThree();
else
doSomethingFour();
}
这种方法有四种不同的潜在结果。我假设我应该为 100% 的代码覆盖率编写四个不同的测试用例。对于我应该如何命名这些测试用例,是否有标准实践/模式?还是人们通常会制作一个巨大的测试用例?
解决方案
在命名测试时需要实现一些目标。请记住,当您运行多个测试时,如果由于更改导致回归,您可能会看到许多失败的测试。然后,理想的情况是,从失败和通过测试的模式中,您可以立即(甚至无需进入代码或启动调试器)推断出问题所在。
因此,从诊断输出(包括失败测试的名称)中,您想知道
- 对于每个失败的测试,哪个类/方法正在测试中。
- 测试失败的场景是什么。
- 预期的结果是什么
在某种程度上,这已经由测试框架的默认输出提供。例如,您可以获得每个失败测试的文件名和类名。但是,即使您知道它是FooTest
file中的类,那么知道这一点并失败FooTest.java
仍然不是太有启发性。此外,测试框架断言 - 当失败时 - 还指示预期值和实际值。对于某些测试,可能很清楚地知道这是预期的结果,但却是实际结果。然而,知道预期输出是 19 可能会更有帮助,它是第八个素数。test15
test21
19
20
解决上述问题的测试名称的常见模式是:
<method under test>_<scenario being tested>_<expected outcome>
例如
process_noFieldsInitialized_shallDoOneAndThree
但是还有更多的命名约定,它们基本上涉及相同的主题,但方式略有不同。
值得一提的是,在这个方向上还有一条思路:与其考虑伟大的解释性测试名称,不如让您的测试代码更具可读性,以便可以立即在测试代码中看到所有信息。对我来说,这不是一个矛盾:当然,代码应该易于阅读。但是,代码在实现级别并使用具体值,而测试名称可以在语义/用户域级别,并且可以描述抽象场景:想象一下,在测试某个函数时,foo
您想测试foo
被调用的场景42 以上的数字。在您的测试实现中,您必须选择一个数字,可能是 43,但也可能是 50。但是,在您的测试名称中,您仍然可以清楚地说明测试的内容:foo_withArgumentAbove42_shallProvideTheAnswer
.
现在,来到您的第二个问题:您是否应该将所有四个场景放入一个测试用例中,或者更一般地说,是否应该将一种方法的所有测试放入一个测试用例中。让我重复上面的目标:从失败和成功的测试用例的模式中,理想情况下您应该能够立即推断出问题所在。这导致得出的结论是,您应该针对不同的方面/场景进行不同的测试。在您的情况下,将有四个测试用例。如果一种情况失败,您将立即知道是哪一种。如果您将所有场景放在一个测试用例中,您随后将不得不弄清楚问题到底是什么。
更新:有四个测试而不是一个可能意味着一些代码重复。显然这是不希望的。因此,当遵循概念为不同的场景/方面进行单独的测试时,请让自己熟悉“参数化测试”或测试辅助方法等概念。
推荐阅读
- python - matplotlib | 在条形图中设置最大 y 轴值
- reactjs - 当新值与旧值相同时,有没有办法触发 useState 钩子
- g++ - 由于编译器问题,Mathematica 包构建失败
- sql - 在插入之前验证和比较日期时间
- java - 如何使用返回 Mono 的函数过滤列表
在 Java 中? - kubernetes - 无法使用 Kubernetes Pod 中的 IAM 角色通过直接命令挂载 s3fs
- html - 我的客户端网页左侧有多余的边距
- docker - Docker:多个网络,一个容器和端口
- php - 如何使用 Ion 在 sql php android 中进行搜索?
- spring - 使用 apache camel 通过 imaps 连接到 ms exchange 共享邮箱失败并出现错误 AUTHENTICATE failed