如何为同一方法命名不同的测试?

3

如何为具有多个不同流程的方法命名测试?

例如,假设我有一个方法process(),它根据对象的字段而表现出不同的行为:

Original Answer翻译成"最初的回答"

public void process () {

    if (this.someField1 == null) {
        doSomethingOne();
    else
        doSomethingTwo();

    if (this.someField2 == null) {
        doSomethingThree();
    else
        doSomethingFour();
}

使用这种方法可能会有四种不同的结果。我假设我应该编写四个不同的测试用例来实现100%的代码覆盖率。是否有标准的实践/模式来命名这些测试用例?还是人们通常制作一个大型测试用例?

这种方法可能会产生四种不同的结果,因此您需要编写四个不同的测试用例以实现100%的代码覆盖率。对于这些测试用例的命名,是否有标准的惯例或模式尚不清楚,您可以根据自己的需求进行命名。一般情况下,人们更倾向于编写多个小型测试用例,而不是一个巨大的测试用例。

最初的回答:

3个回答

4

在为测试命名时,需要实现一些目标。请记住,在运行多个测试时,由于更改可能导致回归,您可能会看到许多失败的测试。那么,理想情况是,从失败和通过测试的模式中,您可以立即(甚至不需要进入代码或启动调试器)推断出问题所在。

因此,您希望从诊断输出中(包括失败测试的名称),了解以下信息:

  • 每个失败的测试对应的类/方法。
  • 测试失败的场景是什么。
  • 期望的结果是什么。

测试框架的默认输出已经在某种程度上提供了这些信息。例如,您可以获得每个失败测试的文件名和类名。但是,即使您知道它是位于文件FooTest.java 中的FooTest 类,知道test15test21 失败还是没有太多启示。此外,当测试框架的断言失败时,也会提示预期值和实际值。对于某些测试来说,了解预期的值是19,而实际的结果是20也足够清楚了。但是,了解预期输出是19,是第八个质数,则更有助于排查问题。

为测试命名的常见模式解决了上述问题:

<method under test>_<scenario being tested>_<expected outcome>

例如
process_noFieldsInitialized_shallDoOneAndThree

但是还有一些其他的命名约定,基本上涉及相同的主题,但以稍微不同的方式进行。
值得一提的是,也有一种思路:不要考虑更好的解释性测试名称,而是使你的测试代码更易读,以便所有信息都可以立即在测试代码中看到。对我来说,这并不矛盾:代码应该易于阅读,当然。但是,代码处于实现级别并使用具体值,而测试名称可以在语义/用户域级别上,并描述抽象场景:假设在测试某个函数foo时,您想要测试的场景是调用foo时使用了某个大于42的数字。在测试实现中,您必须选择一个数字,可能是43,也可能是50。但是,在测试名称中,您仍然可以清楚地表明测试的内容:foo_withArgumentAbove42_shallProvideTheAnswer
现在,谈到您的第二个问题:您是否应将所有四个方案放入一个测试用例中,或者更一般地说,一个方法的所有测试是否都应该进入一个测试用例中。让我重申以上的目标:从失败和成功的测试用例的模式中,您理想上应该能够立即推断出问题所在。这导致您应该为不同的方面/场景编写不同的测试。在您的情况下,将有四个测试用例。如果一个场景失败,您将立即知道是哪个场景。如果将所有方案都放入一个测试用例中,则随后将不得不找出实际问题是什么。
更新:拥有四个测试而不是一个测试可能意味着会有一些代码重复。显然,这是不希望出现的。因此,当遵循为不同的场景/方面编写单独的测试的概念时,请熟悉“参数化测试”等概念,或者测试帮助方法。

感谢您不仅解释了测试命名规范,还解释了背后的思维方式。 - undefined
很遗憾看到这样一个好答案没有更多的投票。Stack Overflow应该把这种答案放在搜索结果的第一页。 - undefined
Dirk,你的帖子说这是一个“常见模式”,但我在互联网上没有找到任何东西(或者可能我没有找对地方)。你有任何外部来源吗? - undefined
嗨,Eric,以下是一些参考资料:https://dzone.com/articles/7-popular-unit-test-naming,https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices - undefined

1

就个人而言,我会选择以下方式:

  • process_someField1IsNull_doesSomethingOne
  • process_someField1IsDefined_doSomethingTwo
  • process_someField2IsNull_doesSomethingThree
  • process_someField2IsDefined_doesSomethingFour

但我认为这是个人偏好的问题。最重要的是找到适合你和你的团队的约定。

或者人们通常会创建一个巨大的测试用例吗?

不,我不建议这样做。最佳实践是每个测试方法只有一个“测试”或断言。


0
在我个人看来,你应该像srk上面建议的那样,每个方法理想情况下应该有一个测试用例。这个方法应该包含所有不同的测试场景。这也是最佳实践所说的。
我建议你只使用一个名为test_process()的单一测试方法,并在其中进行断言。确保你不要在其他各种测试方法中重复相同的方法测试,这有助于使测试用例简单和清晰。

我认为这也是我的理想情况。但是对于更长、更复杂的方法,我怀疑这是否仍然成立。我理解一个方法对应一个测试的逻辑阻塞,但我也看到每个场景一个测试的吸引力。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接