根据我的理解,在TDD中你必须首先编写一个失败的测试,然后编写代码使其通过,然后重构.但是,如果您的代码已经考虑了您要测试的情况怎么办?
例如,假设我是TDD的排序算法(这只是假设).我可能会为几个案例编写单元测试:
输入= 1,2,3
输出= 1,2,3
输入= 4,1,3,2
输出= 1,2,3,4
等...
为了让测试通过,我最终使用了一个快速的肮脏的泡泡排序.然后我重构并用更有效的合并排序算法替换它.后来,我意识到我们需要它是一个稳定的类型,所以我也为此编写了一个测试.当然,测试永远不会失败,因为merge-sort是一种稳定的排序算法!无论如何,我仍然需要这个测试,因为有人再次重构它以使用不同的,可能不稳定的排序算法.
这是否打破了始终编写失败测试的TDD口头禅?我怀疑有人会建议我浪费时间来实现一个不稳定的排序算法,只是为了测试测试用例,然后重新实现merge-sort.你经常遇到类似的情况,你做了什么?
首先编写失败的测试然后让它们运行有两个原因;
首先是检查测试是否实际测试了您为其编写的内容.首先检查它是否失败,您更改代码以使测试运行,然后检查它是否运行.这看起来很愚蠢,但我曾经多次在我添加了一个代码测试,这些代码已经运行以后发现我在测试中犯了一个错误,导致它总是运行.
第二个也是最重要的原因是阻止你写太多的测试.测试反映了您的设计,您的设计反映了您的要求和要求的变化.当发生这种情况时,您不希望重写大量测试.一个好的经验法则是让每个测试都失败只有一个原因,并且由于这个原因只有一个测试失败.TDD尝试通过为每个测试,每个功能以及代码库中的每个更改重复标准的红绿重构周期来强制执行此操作.
但当然,规则被打破了.如果您记住为什么首先制定这些规则,您可以灵活处理它们.例如,当您发现测试有多个测试时,您可以将其拆分.实际上,您已经编写了两个您之前未见过的新测试.打破并修复代码以查看新测试失败是一种仔细检查的好方法.
我怀疑有人会建议我浪费时间来实现一个不稳定的排序算法,只是为了测试测试用例,然后重新实现merge-sort.你经常遇到类似的情况,你做了什么?
那么让我成为推荐吧.:)
所有这些都是在您一方面花费的时间与您减少或减轻的风险以及您获得的理解之间的权衡.
继续假设的例子......
如果"稳定性"是一个重要的属性/特性,并且您没有通过使其失败来"测试",则可以节省执行该工作的时间,但是会产生测试错误并且始终为绿色的风险.
另一方面,如果您通过破坏功能并观察其失败来"测试测试",则可以降低测试风险.
而且,通配符是,你可能会获得一些重要的知识.例如,在尝试编写"错误"排序并使测试失败时,您可能会更深入地考虑对要排序的类型的比较约束,并发现您使用"x == y"作为用于排序的equivalence-class-predicate但实际上"!(x 所以我说错了'花费额外的时间让它失败,即使这意味着故意破坏系统只是为了在屏幕上暂时获得一个红点',因为虽然这些小"转移"中的每一个都会发生一些时间成本,每隔一段时间就会为你节省一大笔钱(例如oops,测试中的错误意味着我从未测试过我系统中最重要的属性,或者oops,我们对不等式谓词的整个设计是混乱的向上).这就像玩彩票一样,除了从长远来看对你有利的几率; 每周你花5美元买票,通常你输了但是每三个月就赢一次1000美元的累积奖金.