首页 > 解决方案 > 如何为同一方法命名不同的测试?

问题描述

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

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

public void process () {

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

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

这种方法有四种不同的潜在结果。我假设我应该为 100% 的代码覆盖率编写四个不同的测试用例。对于我应该如何命名这些测试用例,是否有标准实践/模式?还是人们通常会制作一个巨大的测试用例?

标签: unit-testingjunit

解决方案


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

因此,从诊断输出(包括失败测试的名称)中,您想知道

  • 对于每个失败的测试,哪个类/方法正在测试中。
  • 测试失败的场景是什么。
  • 预期的结果是什么

在某种程度上,这已经由测试框架的默认输出提供。例如,您可以获得每个失败测试的文件名和类名。但是,即使您知道它是FooTestfile中的类,那么知道这一点并失败FooTest.java仍然不是太有启发性。此外,测试框架断言 - 当失败时 - 还指示预期值和实际值。对于某些测试,可能很清楚地知道这是预期的结果,但却是实际结果。然而,知道预期输出是 19 可能会更有帮助,它是第八个素数。test15test211920

解决上述问题的测试名称的常见模式是:

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

例如

process_noFieldsInitialized_shallDoOneAndThree

但是还有更多的命名约定,它们基本上涉及相同的主题,但方式略有不同。

值得一提的是,在这个方向上还有一条思路:与其考虑伟大的解释性测试名称,不如让您的测试代码更具可读性,以便可以立即在测试代码中看到所有信息。对我来说,这不是一个矛盾:当然,代码应该易于阅读。但是,代码在实现级别并使用具体值,而测试名称可以在语义/用户域级别,并且可以描述抽象场景:想象一下,在测试某个函数时,foo您想测试foo被调用的场景42 以上的数字。在您的测试实现中,您必须选择一个数字,可能是 43,但也可能是 50。但是,在您的测试名称中,您仍然可以清楚地说明测试的内容:foo_withArgumentAbove42_shallProvideTheAnswer.

现在,来到您的第二个问题:您是否应该将所有四个场景放入一个测试用例中,或者更一般地说,是否应该将一种方法的所有测试放入一个测试用例中。让我重复上面的目标:从失败和成功的测试用例的模式中,理想情况下您应该能够立即推断出问题所在。这导致得出的结论是,您应该针对不同的方面/场景进行不同的测试。在您的情况下,将有四个测试用例。如果一种情况失败,您将立即知道是哪一种。如果您将所有场景放在一个测试用例中,您随后将不得不弄清楚问题到底是什么。

更新:有四个测试而不是一个可能意味着一些代码重复。显然这是不希望的。因此,当遵循概念为不同的场景/方面进行单独的测试时,请让自己熟悉“参数化测试”或测试辅助方法等概念。


推荐阅读