程序员对TDD这个词一定不陌生,近几年比较火。
英文全称Test-Driven Development,测试驱动开发。
它要求在编写某个功能的代码之前先编写测试代码,然后只编写使测试通过的功能代码,通过测试来推动整个开发的进行。
下面这段是粘的(来自百度百科),列举了TDD相比传统开发模式的一些优势:
1) TDD根据客户需求编写
测试用例,对功能的过程和接口都进行了设计,而且这种从使用者角度对代码进行的设计通常更符合后期开发的需求。因为关注用户反馈,可以及时响应需求变更,同时因为从使用者角度出发的简单设计,也可以更快地适应变化。
2) 出于易测试和测试独立性的要求,将促使我们实现松耦合的设计,并更多地依赖于接口而非具体的类,提高系统的可扩展性和抗变性。而且TDD明显地缩短了设计决策的反馈循环,使我们几秒或几分钟之内就能获得反馈。
3) 将测试工作提到编码之前,并频繁地运行所有测试,可以尽量地避免和尽早地发现错误,极大地降低了后续测试及修复的成本,提高了代码的质量。在测试的保护下,不断重构代码,以消除重复设计,优化设计结构,提高了代码的重用性,从而提高了软件产品的质量。
4) TDD提供了持续的
回归测试,使我们拥有重构的勇气,因为代码的改动导致系统其他部分产生任何异常,测试都会立刻通知我们。完整的测试会帮助我们持续地跟踪整个系统的状态,因此我们就不需要担心会产生什么不可预知的副作用了。
6) TDD可以减轻压力、降低忧虑、提高我们对代码的信心、使我们拥有重构的勇气,这些都是快乐工作的重要前提。
7)快速的提高了开发效率
当我看到这些优势后,我为之一震,这个东西好,但仔细思考后,觉得很多地方并不是那么容易的,也不像TDD宣称得那么乐观。
下面针对上述每一条优势,谈谈我的看法。
针对第一条:
“TDD根据客户需求编写测试用例”,“从使用者角度对代码进行设计”,但经过无数实践证明,软件开发的最大困难在于用户需求的不确定性,根据用户需求编写测试用例,除非针对一些很简单或者很明确的需求,否则你的测试用例根本不能真正反映用户的需求。TDD从一定程度上提前做了一个假设,那就是“需求可以在实现之前明确下来”,这是不现实的。在实际的软件开发中,用户需求和外部环境的不稳定性会导致软件需求难以把握。只有让用户看到了运行的软件,用户才能驱使软件朝着他想要的方向前进,通常需求和设计都会不断调整。
针对第二条:
我不否认测试可以驱使我们写出更高质量的代码,但这是测试的作用,并不是TDD的作用,“在没有测试用例失败之前,不要写任何一行代码”这种极端的方式,会导致我们的设计不是迎合用户需求,而是迎合测试用例,而如前面所说,测试用例很难在一开始就符合用户需求。我们完全可以在完成系统功能的同时,完成单元测试,然后通过重构的方式来改善既有代码的质量。
针对第三条:
不可否认,“频繁地运行所有测试,可以尽量地避免和尽早地发现错误,极大地降低了后续测试及修复的成本,提高了代码的质量。”但如果把这些放在代码之前,那么我们如何保证自己的测试用例写得恰当,一旦需求变更,或者对需求理解有误,那么修改测试用例,意味着我们的编码全部废弃了,不要小看这个成本,很可能会出现这种情况:我们花成倍的时间去维护我们的测试用例,却不能如期交付我们的软件。
第四条,第五条,第六条提到的也是一样,并不是TDD的功劳,是自动化测试的功劳。自动化测试并不是什么新东西,从Junit出现的那天,自动化测试就已经很成熟了。TDD包含自动化测试,如果TDD的所有优势都来源于自动化测试,那么TDD完全是一个大忽悠。
总结:
看到TDD,我就想到了瀑布模型。TDD强调“
先理解清楚需求,把它转化为测试用例,然后再来实现和重构“,细一琢磨,这不就是瀑布模型嘛?强调需求先于实现,瀑布模型用文档表达需求,而TDD只不过是把需求文档换成了测试用例而已。所以我认为,TDD不是什么新东西,只不过在瀑布模型的基础上换了身衣服,带了个自动测试的帽子而已。它将不可避免地面临和瀑布模型相同的问题:“
忽略了软件需求的产生是一个在实际运行中不断调整探索完善的过程。”
个人愚见,勿喷。