为什么程序员厌恶写单元测试?为什么他们更厌恶在编码前写单元测试?你不需要回答,我已经听到很多借口了。我有一套理论,实际上正是这些问题的真正原因。
大多数开发者从来没有认真尝试过测试先行的开发。或者他们尝试过,但不能在一个良好的环境(他们能够明白他们自己在做什么的环境)下。但是前者更多。所以他们的理由是我们没有时间写单元测试或单元测试不能保障你的代码。他们是出于恐惧,而不是出于内心的勇气,尽量掩盖自己的错误,而不是如何变得更有效率。
你如何解决一个软件问题?在学校里,老师们是怎样教你处理问题的?你做的第一件事是什么?你考虑这如何解决他?你问道”我该写什么代码来解决这个问题?”但是这问题很肤浅。你先问的不应该是”我该写什么代码来解决这个问题?”,而是”我如何知道这个问题解决了?”
我们被教育成:我们总是假设已经知道如何来判断我们的解决方法是正确的。这是一个愚蠢的假设。就像”猥亵”一词,我们只有看到这种行为时时才能够明白这个词汇。我们相信在写代码之前,我们不需要思考关于它需要做什么,这个思想已经根深蒂固了。对我们大多数来言,很难改变。
所有拥有上面想法的人注意,下面就是采用测试先行的开发所带来的利益。我一直在体验这些事情,但是不要相信我的话。你自己尝试一下:
- 单元测试证明了你的代码确实没问题。这就意味着你的bug更少。确实,单元测试不能代替系统测试和acceptancetesting。但是单元测试确实是他们很好的支持。记住:让SQA发现的bug越少越好
- 你得到了一个低成本的回归测试环境。你可以在任何时间返回,不仅能了解是什么问题,而且能找到bug在哪。许多团队把单元测试放在发布版本中。这是一个低付出的寻找bug的方式。
- 你可以优化设计而不用损坏代码。这实际上是KentBeck中提到TDD开发的第三步,重构。因此测试驱动的代码通常不需要重构。
- 用单元测试来写代码比不用更有趣。你知道你的代码需要做什么,接着你将其实现了。即使你没有一个正常工作的系统,你可以看到你的代码确实能运行而且质量好。你有一种”I’vedoneit!”的良好感觉。
- 单元测试可以精确描述进度。你不需要等一个月来把系统的所有部分整合起来。即使没有一个正常工作的系统,你也可以展示进度。你不仅可以说你已经写了代码,而且你确实可以说这段代码是没问题的。当然,这也是另一个传统的编程教学教我们忽略的一个区别。”Done”不仅仅意味着你写完代码,也看到这段代码能用。”Done”意味着代码确实能在系统中运行,而且没有bug。运行单元测试是向后者接近的一步。
- 单元测试是样例代码的一种形式。我们都遇到过我们不会用的库函数和类。然后我们第一个去的地方就是样例代码。样例代码就是文档。但是我们通常不会为内部代码准备样例。所以我们就得看源代码或者是浏览系统的剩余部分。因为写这个代码的Bob已经不在这个公司了,所以我们不能问他这是如何工作的。但是单元测试就是文档。所以当你不能记住如何用类foo时,就读单元测试来搞明白。
- 测试先行的开发强迫你在编码之前就计划好。先写测试强迫你再考虑,再次思考你的设计,以及在你写代码之前必须要完成什么。这不仅让你集中注意,也优化了设计。
- 测试先行的开发减少了bug的开销。在早期发现的bug容易修复,而在后期发现的bug可能是多次修改后造成的综合结果,并且我们不知道是哪次修改引起这个bug。首先我们要找到bug,接着回想这代码是怎么工作的(因为我们已经几个月没看他了),最后我们终于理解并提出解决方案。任何能够减少从制造bug到检测出bug之间的时间好像都是胜利。我们认为自己足够幸运以至于在交给客户或sqa之前用几天的时间就会找到bug。但是如果能够在几分钟内找到bug怎么样呢?这就是测试先行的开发对捕获bug能够做到的事。
- 单元测试要比代码审查好。有人说代码审查要比测试好,因为使用代码审查来检测并修复bug要比测试廉价的多。在代码交付后,修复bug要昂贵的多。我们越早检测修复bug,事情就会越容易,越廉价,越好。这是codereview的好处:codeinspections在几天内捕获bug,而不是几个月。但是test-first在几分钟内捕获bug,而不是几天。他甚至比codeinspections更廉价
- 单元测试可以优化设计。测试一段代码强迫你去定义这段代码负责什么。如果你可以轻松地完成,那就意味着代码的功能定义良好,因而它内聚性是高的。再者如果你能对你的代码进行单元测试,那就意味着你可以轻松地将它绑定到系统其他部分就像绑定到测试一样。因而它与其他模块的耦合性低