你如何解决TDD中的无限回归问题?

时间:2010-01-21 22:56:42

标签: unit-testing testing tdd

如果我编写测试代码来测试我的代码,测试代码可能有错误,因此需要进行测试,当我的代码更改时,我的测试代码可能需要更改。无限重复。

这个问题是如何解决的(在实践中和理论上)?

8 个答案:

答案 0 :(得分:5)

测试测试代码,代码测试测试。

当您编写测试时,然后编写足够的代码来运行它,测试失败。然后你编写代码让它通过。如果不是这样 - 如果它在之前通过你编写代码,或者如果它在之后失败,那么就会出错。如果在编写代码之前测试通过,那么测试显然有问题 - 修复它,直到你变红并得到你预期的失败。如果测试是红色的并且在编写代码后没有变为绿色,那么两个问题之一是错误的:测试或代码。搞清楚,修复它,继续前进。

答案 1 :(得分:2)

实际上,通过确保测试在通过之前失败。 TDD并没有神奇地删除代码中存在错误的所有能力,它有望减少错误数量,但它作为一种设计技术更为重要。

真正改善错误计数的地方就是重构时。当我重构并且打破了一些由测试建立的旧行为时,测试已经多次保存了我的培根。

当测试在通过之前失败时,您可以确信您实现的代码实际上是以使测试通过的方式运行,使测试成为有效的。如果你更改破坏测试的代码,那么你需要考虑哪一个是正确的,并相应地进行调整。

当我读到你的问题时,我看到了TDD将阻止所有错误的潜在期望。它不会。但它会阻止一些。更重要的是,它可以在您重构时防止错误,让您随着时间的推移改进设计而不必担心会退步。

但TDD真正发挥作用的是驱动设计。它可以确保设计正确地考虑依赖性,它是模块化的,并且它完成了您期望它做的事情(而不是做正确的事情 - 必须是集成或验收测试的一部分)。

编辑:(回应评论)我理解你的问题,并试图回答它。由于我没那么成功,我会再试一次。

如果首次看到测试失败然后通过,则会处理它有一个无法测试任何内容的错误的基本概念(代码验证测试,测试测试代码)。它显然取决于要传递的生产代码,因此它会测试一些东西。更重要的是,它不能真正做到。还有进一步的测试层次(整合,接受,也许是一般的质量保证),将解决更深层次的问题。

但我的首要观点是挑战我所理解的问题的前提:如果测试本身可能存在错误,TDD如何提供100%无错误的代码。我对这个前提的回答是它不能。它做了别的事(驱动器设计)。我希望澄清事情。

答案 2 :(得分:1)

这个想法是单元测试没有复杂的逻辑...每个应该基本上由一个动作和一个关于动作的结果或行为的断言或断言组成。如果有任何循环或分支逻辑,那就没什么了......没有什么可能会有任何错误,不是那么明显你不会错过它。所以是的,正如其他人所说,你只是不为你的测试编写测试。

答案 3 :(得分:1)

我最近在工作中与某人讨论过这件事。提出这个问题的人有一个公平的观点,但最终,单元测试是一种实用的,经过验证的技术。 TDD进一步增加了“测试优先”方面,进一步降低了测试错误的可能性,因为在编写任何生产代码之前它应该失败。虽然测试可以被窃听,但在我看来,这个问题更像是一个哲学辩论,而不是一个实际的障碍。

当有问题的代码构成其他单元测试夹具将使用的可重用框架或实用程序测试类时,您需要测试代码来测试测试的论点只对我有所帮助。

示例: 在NUnit 2.5之前,我们有可重用的数据驱动测试类。它被许多其他测试所使用和依赖,而且它相当复杂。当然很复杂,有虫子。所以我们对测试类进行了单元测试。 ..然后当NUnit 2.5出来时,我们交换了所有测试以使用它并丢弃了我们自己的实现。

另一方面,编写良好的测试代码很简单,不包含特殊的逻辑/分支,有助于围绕生产代码构建脚手架。在可能的情况下,我们应该始终利用其他经过良好测试的框架中的功能,而不是在我们的测试类中执行任何逻辑。如果常规单元测试代码变得复杂到足以让某人认为它可能需要测试,我认为这种方法可能存在缺陷。

答案 4 :(得分:0)

写出非常好的测试代码。记录下来,在编写时仔细考虑,并在方法中采用有条理的方法。此外,如果您将单个测试尽可能地缩短,则可以增加代码覆盖率,同时尽可能保持创建小错误(和可见)的错误。

答案 5 :(得分:0)

单元测试并不意味着100%防范错误。它只是一种提高代码质量的技术。从来没有练过TDD,人们会认为如果添加一个要通过的测试,代码的整体质量将无法提高,DOH!

解决单元测试的测试问题。这正是您首先使测试失败的原因 - 它是为了提高测试质量。这里没有绝对的,但这种做法确实有帮助。就像他们说的那样,测试测试代码和代码测试测试。这比没有测试好。

至于在他们休息时回去测试并修复它们,那么意味着发生。如果测试结果良好(即精确粒度)并测试一个非常狭窄的用例,他们会提醒您实际代码将在哪里中断。

单元测试作为回归工具非常有用。宏观回归(如代码编写后的几天,几周,几年)和微观回归(编写代码时)。顺便说一下,我完全发明了这些术语。如果它们是Martin Fowler或Bob叔叔使用的实际术语,那么这就意味着我就像他们一样聪明:)开个玩笑。

很长一段时间回归得到了很好的理解,你在编写代码后几个月就更改了代码,测试会提醒你什么是坏的。另一方面,微观回归是指编写代码并慢慢添加功能。如果您没有测试,那么您可能会从代码的使用位置进行测试,只需修改该代码即可完成各种场景。以后的代码很可能会破坏早期的用例。

使用TDD,您实现的功能的所有用例(测试)都会保留。这意味着你几乎可以保证,你以后添加的任何内容都不会破​​坏更为常见的代码。

答案 6 :(得分:0)

尽可能简单地编写测试。

然后你将有一个良性循环,你的代码变得尽可能简单,以测试测试。

或者流行的理论如此。

答案 7 :(得分:0)

听起来你正在考虑编写单元测试证明是正确的。这是两件事。测试代码提供了一组已知的输入并验证输出 - 它们应该非常简单。设置输入,执行,验证输出。测试仅检查是否为您在测试中实现的方案生成了预期输出。如果您编写的测试非常复杂,以至于需要对它们进行测试,那么您需要大大简化测试。您不应该为测试代码编写测试代码。