针对接口写测试用例
这个情况在传统工业里是不可想象的。你无法想象波音飞机在开始总装之前没有对它的零件进行过像样的测试,但是你却常常看到我们对一大堆没有进行过单元测试的代码进行集成。这个模块有内部逻辑错误吗?它有内存泄漏吗?它能够应付那些极端的边界条件吗?它达到了需求的要求了吗?不知道,先拼起来再说,到时候测试发现不了问题就会放我们过关的。然后你盯着每周的bug 列表看,看到bug 数渐渐下降,渐渐的接近出厂要求,然后你擦擦头上的冷汗:“感谢上帝,看来这次又过关了”。但是,难免会有一天,你的邮箱里塞满了来自用户的抱怨,告诉你你的程序又在某个你想不到的地方出了问题。
问题在哪?问题在于我们要求程序员在完成开发之后再完成一套东西的开发,而这些东西并不是要开发的软件的一部分,并且将在项目结束时被抛弃。对程序员而言,这等于叫他额外的多完成一些原本不需要的任务,这是很难被接受的,即使他能理解这样做的重要性。这是人性的弱点。那么,我们如何让测试更进一步的深入开发过程,尽可能保证软件每个组件的质量呢?这就要求我们放手让测试驱动开发的过程,让对需求的承诺直接的传递到每个组件的开发当中。
在详细设计的过程当中,需求总是可以分解到模块,并且确定了模块之间的接口。之后才是正式的开发。于是对各个模块来说,“这个组件要实现什么功能?”“它将如何被使用?”这样的需求总是完整的被体现在了各个模块的接口上,也就是说,保证对接口的使用能够正确无误的进行,就保证了这个模块的最终质量。那么,我们先走一步,针对模块的接口写出测试代码,这样在以后开发的时候,就可以确定我们的模块是否达到了我们的需求。也就是说,我们把单元测试提前了,提前到单元代码的开发之前。
先写测试代码的带来了很多好处。首先,在很多时候,需求是不清晰或者说不完整的,那么写测试代码的过程就是使需求清晰化的过程,这使以后的开发免除了很多麻烦和争执。其次,这使得我们得以在整个开发过程中保持一套详尽的单元测试代码,而这在代码重构里是必不可少的。最后,先写测试代码会影响程序员的心理,使他们重视用户的需求和体验,而不是仅仅打算实现模块的功能和避免被发现错误。
然后,我们在整个开发过程中将由这些测试来决定代码如何编写,因为这些测试代码代表的是接口的标准,而接口正是需求的化身。对于这个开发模式,Peter Coad 给出了以下的描述:
a.. 编写和保持一套详尽的单元测试。
a.. 要先建立相关的单元测试和验收(acceptance)测试,然后根据测试编写代码。
a.. 由测试来决定如何编写代码。
下面我们来总结我们上面提到的要点:
1)针对接口开发,使接口代表需求
2)用测试评价接口是否符合需求,并且在开发过程中保持足够详尽的测试
3)在代码的修改、重构等变化时,用测试保证代码质量
在更高层的视野看来,测试驱动编程事实上是把测试对软件整体质量的保证引入到软件单元的开发中来,使得整个开发过程中的质量得到更进一步的监护 。