“通过单元测试可以改善代码质量”这一观点已经得到广泛认可。培训师、顾问兼咨询师Michael Feathers在近的帖子中对其提出了质疑。他谈及单元测试、集成测试、TDD和净室软件开发(Clean Room Software Development),认为代码质量是反复思考的结果,仅靠解决bug无法获得。M3P的独立咨询师Steve Freeman进一步阐述了Michael的观点,从“认知方面对TDD进行了分析”,并解释了TDD的好处从何而来。

  Michael认为,利用测试找Bug来改善质量的想法是有不足之处的:

  对于单元测试,常见的理论是“通过解决测试找到的bug,软件的质量得以提升”。乍听起来,好象没错儿。测试有通过或失败两种结果,一旦失败,我们知道肯定是有什么地方出了问题,要修复它。假如你赞同这个说法,你会预期在做集成测试时发现更少的集成错误,在做单元测试时也是一样。这个观点貌似挺好,不过它是错误的。能够证明这一点的佳方法是:将单元测试与另一种提高质量的方法相比较,而且这种方法有着很好的度量效果。

  为了证明他的观点,Michael提到净室软件开发(Clean Room Software Development),这是一种在上个世纪八十年代曾被使用的开发方法。根据Michael所述,净室方法不包括任何单元测试过程:

  净室方法背后的观念,是要通过更严格的开发纪律来提高质量;在净室中,你要为每一小短代码写逻辑断言;在代码复查时,你还要证明代码的功能和你写的断言完全符合,功能不多也不少。这种方法非常严格,甚至比我所说还要极端,因为净室方法的另一个宗旨是:不能有单元测试。一个都没有。毫无必要。代码开发完成之后,只要被复查过被认为是完全正确的。的测试是在功能层面的随机测试。

  使用净室方法的结果很有趣:不经任何单元测试,代码质量也提高了。净室方法和TDD方法的相似之处在于:迫使开发人员不断复查、重构并改进他的代码。Michael的结论是:

  我认为,我们不能机械地看待测试。单元测试并不能在“单元”这个层次上通过抓到错误来改进质量。而且,集成测试也不能在“集成”这个层次上通过抓到错误来提高质量。实际上背后的道理难以言说。质量是反复思考的结果??严谨的反复思考。这是关键。强化纪律的技术一定会提高质量。

  从Michael的帖子出发,M3P的独立咨询师Steve Freeman进一步阐述了这个观点,并谈到“对TDD在认知上的分析”。开发人员的某些决定会影响他们的代码:

  事实证明,人们并没有真正花时间从各种可行的方案中进行权衡,而是使用了“首先契合(first-fit)”的方法,即将已知的解决方案按序排列,然后选择第一个看上去好的方案。所有这些都是在潜意识下发生的。在这之后,我们迟钝的理性思维才会想办法证明这个已成事实的决定??我们甚至都不知道这些是如何发生的。

  关键在于不要直接采纳第一个在我们脑海里出现的解决方案,而是要评估不同的可选方案,这是Steve认为TDD有益的原因:

  测试驱动开发打破“首先契合”这种模式匹配,从而发挥了(或应该发挥)作用。通过TDD,我们不再强制用脑海中出现的第一方案来解决问题。我们也不得不远离自己的“安全地带(comfort zone)”来考虑真正需要实现的需求。更重要的是,从“写一个测试开始”迫使我们首先去想真正需要的是什么(要测试什么),然后再用我们专家般敏锐的大脑来得出解决方案。

  Steve举了一个例子来证明他的观点:

  有力的证据是Arlo Belshee所在的小组,他们实现了无序结对编程(Promiscuous Pairing)。他们从经验中发现:相对于成员自己决定结对时间,强制他们每隔几个小时切换结对,这样的生产率高。他们认为,这样可以保持每个人处于“初学者”的心态,也可以像“初学者”那样思考。