在为测试命名时,需要实现一些目标。请记住,在运行多个测试时,由于更改可能导致回归,您可能会看到许多失败的测试。那么,理想情况是,从失败和通过测试的模式中,您可以立即(甚至不需要进入代码或启动调试器)推断出问题所在。
因此,您希望从诊断输出中(包括失败测试的名称),了解以下信息:
- 每个失败的测试对应的类/方法。
- 测试失败的场景是什么。
- 期望的结果是什么。
测试框架的默认输出已经在某种程度上提供了这些信息。例如,您可以获得每个失败测试的文件名和类名。但是,即使您知道它是位于文件FooTest.java
中的FooTest
类,知道test15
和test21
失败还是没有太多启示。此外,当测试框架的断言失败时,也会提示预期值和实际值。对于某些测试来说,了解预期的值是19,而实际的结果是20也足够清楚了。但是,了解预期输出是19,是第八个质数,则更有助于排查问题。
为测试命名的常见模式解决了上述问题:
<method under test>_<scenario being tested>_<expected outcome>
例如
process_noFieldsInitialized_shallDoOneAndThree
但是还有一些其他的命名约定,基本上涉及相同的主题,但以稍微不同的方式进行。
值得一提的是,也有一种思路:不要考虑更好的解释性测试名称,而是使你的测试代码更易读,以便所有信息都可以立即在测试代码中看到。对我来说,这并不矛盾:代码应该易于阅读,当然。但是,代码处于实现级别并使用具体值,而测试名称可以在语义/用户域级别上,并描述抽象场景:假设在测试某个函数
foo
时,您想要测试的场景是调用
foo
时使用了某个大于42的数字。在测试实现中,您必须选择一个数字,可能是43,也可能是50。但是,在测试名称中,您仍然可以清楚地表明测试的内容:
foo_withArgumentAbove42_shallProvideTheAnswer
。
现在,谈到您的第二个问题:您是否应将所有四个方案放入一个测试用例中,或者更一般地说,一个方法的所有测试是否都应该进入一个测试用例中。让我重申以上的目标:从失败和成功的测试用例的模式中,您理想上应该能够立即推断出问题所在。这导致您应该为不同的方面/场景编写不同的测试。在您的情况下,将有四个测试用例。如果一个场景失败,您将立即知道是哪个场景。如果将所有方案都放入一个测试用例中,则随后将不得不找出实际问题是什么。
更新:拥有四个测试而不是一个测试可能意味着会有一些代码重复。显然,这是不希望出现的。因此,当遵循为不同的场景/方面编写单独的测试的概念时,请熟悉“参数化测试”等概念,或者测试帮助方法。