【问题标题】:Should I create a new test method for each assertion?我应该为每个断言创建一个新的测试方法吗?
【发布时间】:2009-12-14 00:54:10
【问题描述】:

我知道这是主观的,但我想遵循最常见的做法。 您通常为每个类方法创建一个测试方法并用多个断言填充它,还是每个断言创建一个测试方法?

例如,如果我正在测试银行帐户的 withdraw 方法,并且我想确保在用户尝试透支帐户或提取负数时引发异常,我应该创建 testOverdaw 和 @ 987654323@,或者我只是将这两个断言组合在一个名为testWithdraw的方法中?

【问题讨论】:

  • 在我看来,你至少应该测试 0 和 max(numeric) ,这很明显,最终拥有一个已知的初始状态并让它们都单独测试会更简单。跨度>

标签: unit-testing tdd


【解决方案1】:

这样想:每个测试都应该独立运行,并执行一组相对离散的功能。如果您想断言您创建的某个方法的三件事是否正确,那么您应该创建一个包含这三件事的测试。

因此,我不得不强烈反对其他回答的人。任意将自己限制在每个测试中的一个断言对您没有任何帮助,只会使您的测试变得笨拙和乏味。最终它可能会让你完全放弃测试——这肯定是一种耻辱:对你的项目和职业生涯不利。

现在,意味着您有编写大型、笨重或多用途测试例程的许可。确实,我想我从来没有写过超过 20 行的文章。

至于知道哪个断言在一个函数中有多个时失败,您会注意到,当断言失败时,nUnit 和 MSTest 都会为您提供描述和链接,这将带您直接进入有问题的行(nUnit 将需要一个集成工具,例如TestDriven.net)。这使得找出故障点变得微不足道。两者都将在函数的第一次失败时停止,并且都使您能够进行调试演练。

【讨论】:

  • 我同意其中的大部分内容,但我发现这种方法有一个缺点。如果您正在执行三个断言来测试三个不同的场景,并且在运行测试时,第一个断言失败。另外两个断言呢?你不知道他们会成功还是失败。你打破了你的三个场景还是只有一两个?有什么想法吗?
  • 好问题。首先,请记住测试中的所有断言都应该是相关的。如果一个失败,它很可能会对其他人产生影响。因此,无论如何,在确定其他人之前,我必须先修复第一个。其次,在我的工作风格中,失败的测试是立即修复的原因。所以在我修好第一个之前,我并不真正担心其他两个。也就是说,我将在一个紧密的循环中修复和测试该功能,直到所有功能都得到验证。所以,如果其他人失败了,我可能会通过修复第一个来修复它们。如果他们没有失败,重新测试会立即告诉我。
  • @joerage 为什么不直接解决问题,重新运行测试,看看其他断言是否失败?
  • 我非常同意一般规则 ONE test = ONE AND ONLY ONE 在每种情况下的断言不正确。大多数时候确实在一个测试中只有一个断言,但在某些情况下,您可以在一个测试中使用多个断言。
【解决方案2】:

就我个人而言,我会为每个断言创建一个测试,否则您必须挖掘以找出失败的原因,而不是从测试名称中明显看出。

如果您必须编写几行代码来设置测试并且不想重复,那么根据您的语言和测试框架,您应该能够创建一组测试,其中每个测试将执行一个运行之前的代码块。

【讨论】:

    【解决方案3】:

    制作多种测试方法;不要将它们合二为一。您的每个测试方法都应测试该方法的一种行为。正如您所说,使用负余额进行测试与使用正余额进行测试是不同的行为。所以,这将是两个测试。

    您希望这样做,以便当测试失败时,您不会被困在试图找出该测试中的哪个部分失败。

    【讨论】:

    • 大多数测试运行程序不会打印出一个行号,以便您判断哪个断言失败了吗?
    • 是的,但是您想从测试名称中找出失败的原因,还是在源代码中查找自测试运行以来可能已更改或未更改的行号?
    • 这是不合理的(否则您没有使用 Visual Studio)。如果您在 Visual Studio 中使用 nUnit 或 MSTest,则只需单击错误即可直接转到代码行。
    • 另一个注意事项:我使用 TestDriven.net 将 nUnit 与 Visual Studio (testdriven.net) 集成。我现在确实使用 MSTest。
    • 顺便说一句,我并不是说您应该测试与一项测试显着不同的行为 - 只是有时可以有多个断言。例如,在我的书中这样的事情是可以的 - 检查是否返回了一个项目并且它是真的: Assert.That(result.Count, Is.EqualTo(1)); Assert.That(result[0], Is.True));
    【解决方案4】:

    一种方法是为每个不同的场景或设置使用一种单独的方法。在您的情况下,您可能需要一种资金充足的情况,以及一种资金不足的情况。并断言在第一个中一切正常,在第二个中相同的操作将不起作用。

    【讨论】:

      【解决方案5】:

      我建议每个断言使用一种测试方法,或者更确切地说,根据预期行为使用一种测试方法。这允许在任何测试失败时更快地定位错误代码。

      【讨论】:

        【解决方案6】:

        我会做出这两个单独的断言。

        第一个表示如果用户定期使用该帐户会发生的有效操作,第二个表示未完成或未正确完成数据清理的情况。

        您需要单独的测试用例,以便您可以根据需要在逻辑上实现测试用例,尤其是在运行所有测试可能非常昂贵的回归场景中。

        【讨论】:

          【解决方案7】:

          testOverdrawtestNegativeWithdrawal 是两个独立的行为。它们应分别进行测试。

          一个好的经验法则是在一个单元测试中只对被测方法执行一个操作(不包括设置和断言)。

          【讨论】:

            【解决方案8】:

            来自 NUnit 文档: “如果一个断言失败,则方法调用不会返回并报告错误。如果一个测试包含多个断言,那么任何跟随失败的断言都不会被执行。因此,通常最好每次尝试一个断言测试。”

            http://www.nunit.org/index.php?p=assertions&r=2.4.6

            但是,没有什么会迫使您遵循最佳做法。如果这个特定项目不值得您花时间和精力进行 100% 细粒度测试,其中一个错误意味着一次测试失败(反之亦然),那么不要这样做。归根结底,它是一种让您以最佳成本/收益平衡使用的工具。这种平衡取决于许多特定于您的场景和特定于每个项目的变量。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2019-06-30
              • 1970-01-01
              • 2016-03-25
              • 1970-01-01
              • 2016-01-14
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多