测试驱动开发
简单的3条测试规则:
第一个也是最明显的一个效果,是程序中的每一项功能都有测试来验证它的操作的正确性。这个测试套件可以给以后的开发提供支援。无论何时我们因疏忽而破坏了某些已有的功能,它就会告诉我们。我们可以向程序中增加功能,或者更改程序结构,而不用担心在这个过程中会破坏重要的东西。测试告诉我们程序仍然具有正确的行为。这样,我们就可以更自由地对程序进行更改。
还有一个更重要但不是那么明显的效果,是首先编写测试可以迫使我们从不同角度看问题。我们必须从程序调用者的有利视角去观察我们将要编写的程序。这样,我们就会在关注程序功能的同时,直接关注它的接口。通过首先编写测试,我们可以设计出便于调用的软件。
此外,通过首先编写测试,我们迫使自己把程序设计为可测试的。把程序设计为易于调用和可测试的是非常重要的。为了易于调用和可测试,程序必须和它的周边环境解耦。这样,首先编写测试迫使我们解除软件中的耦合。
首先编写测试的另一个重要效果,是测试可以作为一种非常有价值的文档。如果想知道如何调用一个函数或者创建一个对象,会有一个测试展示给你看。测试就像一套范例,它帮助其他程序员了解如何使用代码。这份文档是可编译的、可运行的、它保持最新。它不会撒谎。
验收测试
作为验证工具来说,单元测试是必要的,但是不够充分。单元测试验证了系统中小的组成单元应该按照所期望的方式工作,但是它们没有验证系统作为一个整体时工作的正确性。单元测试是用来验证系统中单个机制的白盒测试(white-box test)。验收测试是用来验证系统满足客户需求的黑盒测试(black-box test)。
验收测试由不了解系统内部机制的人编写。这些测试可以有客户直接编写,或者由业务分析师、测试人员以及质量保证专家编写。验收测试是自动执行的,通常使用一种特定的规格描述语言编写,这种语言比较适合非技术人员阅读和使用。
验收测试是关于一项特性的最终文档。一旦客户编写完成了验证一项特性的验收测试,程序员可以阅读那些验收测试来真正地理解这项特性。所以,正如单元测试作为可编译、可执行的有关系统内部结构的文档那样,验收测试是有关系统特性的可以编译、可执行的文档。简而言之,验收测试是真正的需求文档。
在项目迭代的初期,会受到用手工的方式进行验收测试的诱惑。但是,这样做使得在迭代的初期就丧失了由自动化验收测试的需要带来的对系统进行解耦合的促进力,所以是不明智的。在开始第一次迭代时,如果非常清楚地知道必须要自动化验收测试,就会做出非常不同的系统架构方面的权衡。并且,正如单元测试可以促使你在小的方面做出优良的设计决策一样,验收测试可以促使你在大的方面做出优良的系统架构决策。
结论
测试套件运行起来越简单,就会被越频繁的运行。测试运行得越多,就会越快发现与测试的任何背离。如果能够一天多次的运行所有测试,那么系统失效的时间就绝不会超过几分钟。这是一个合理的目标。我们绝不运行系统倒退。一旦它工作在一个确定的级别上,就决不能让它倒退到一个稍低的级别。
然而,验证仅仅是编写测试的好处之一。单元测试和验收测试都是一种文档形式。那样的文档是可以编译和执行的;因此,它是准确和可靠的。此外,编写测试所使用的语言是明确的,并且非常易于其观看者阅读。程序员能够阅读单元测试,因为单元测试是使用程序员编程的语言编写的。客户能够阅读验收测试,因为验收测试是使用简单的表格式语言编写的。
摘录自:[美]RobertC.Martin、MicahMartin著,邓辉、孙鸣译 敏捷软件开发原则、模式与实践(C#版修订版) [M]、人民邮电出版社,2013、22-28、