实践测试驱动开发
作为一个有理想、有追求的程序员,你成天被各种名词包围着,你对其中一个叫做敏捷的东西特别感兴趣,因为它特别强调人的作用,这听着都让做程序员的你感到舒服。为了让自己早日敏捷起来,你从众多的敏捷实践中选择了一个叫做测试驱动开发(Test Driven Development,TDD)的作为你的起始点。因为它对你周遭的环境要求是最低的:它不像结对那样,要求其他人和你一起合作;也不像采用Story那样改变你所在团队的做事方式……你所需要做的,只是在你编写业务代码之前,把测试先写好。这完全是一种润物细无声的做法,根本无需告诉你之外的任何人。就在别人忙碌的找bug时,你便开始享受敏捷带给你的快乐了。顺便带来的好处是,下次在那里和别人争论敏捷的时候,你可以以一个实践者的姿态出现,而不是在那里信口开河。
你不会打无准备之仗,于是,你通读了Kent Beck的那本薄册子。通读之下,你对TDD更是充满了信心。因为“红——绿——重构”的步骤实在是简单得令人发指。好吧!总而言之,你已经信心十足的准备开始TDD,步入敏捷的康庄大道了。
理想很美好,现实很残酷。
当你着手在实际项目中体验TDD的时候,一切变得并不像最初看起来的那样美好。虽然你努力的坚持着TDD的原则,但你经常就会发现某些东西不好测,比如你遇到了数据库,比如你遇到了GUI,比如你遇到了计时器(Timer)。敏捷并非教条,当某些事不可为的时候,你完全可以不那么坚持。于是,你告诉自己,不好测的东西可以不测,这样,至少从心理上来说,你觉得舒服多了。随着工作的继续,你发现,你不能测的东西越来越多,单元测试的覆盖率随着开发的进行正在逐渐降低,一丝恐惧涌上心头。回过头来,再去看Kent Beck的书,你突然觉得,你似乎被骗了,因为Kent Beck的例子貌似全都是逻辑,如果只是逻辑,当然好测了,但现实从来就不是这样。
难道TDD只是看上去很美?
显然,你不愿意就这样放弃,放弃你苦心学来的软件开发秘籍,那些传说中的高手极力推崇的TDD必然有一定道理,TDD确实能够让你感觉很好:能测试的那部分代码确实极大的增强了你对软件质量的信心,而且出错了也确实好找,每次修改代码之后运行测试出现的绿条也确实让你身心愉悦。
那问题到底出在哪呢?你陷入了沉思。
信马由缰,你翻开了自己写过的代码。看着自己写的这些代码,你忽然意识到一个问题,自己遇到的问题并不属于TDD,而是属于单元测试。正如你之前所想到的那样,TDD做法本身的结果是让你感到快乐的。对,一定是单元测试本身出了问题。那单元测试出了什么问题,很显然,一大堆不能测试的部分让单元测试变得很难写,降低了单元测试的覆盖度。那是不是这会是一个无解的问题呢?你显然不愿意就此放弃,所以,顺着这个思路继续向前。
TDD之所以让你安心,主要是每次编写代码之后,运行测试会出现一个绿条,告诉你测试通过。这样,你可以放心大胆的向前继续,因为你的代码并没有破坏任何东西。究竟是什么让你感到不安,显然是那些测试没有覆盖到的代码。你又仔细翻看了一下那些没有测试覆盖的代码,你的思路一下子清晰起来。之所以这部分让你不安,因为里面除了那些确实不好测试的部分之外,里面还有一些逻辑。如果只是那些真正不好测试的部分没有被测试覆盖到,你会觉得心里还有一些安慰。你确定了,真正使你不安的就是与不好测试的代码共存亡的这些逻辑部分。
如果测试可以覆盖到这些逻辑的部分,至少从感情上来说,就可以接受了。那怎么才能让这些部分被测试覆盖到呢?你仔细观察着那些没有测试的代码,如果这样做,这个部分就可以测试了,如果那样做,那个部分也可以测试了,一来二去,这些貌似不可测试的代码可以分解出许多可以测试的部分。
你的心情一下子好了许多,因为这么做终于可以让测试的覆盖度达到让你心理上可以接受的范围。不过,新的问题也随之而来。我在做什么?拆来分去,这不就是设计吗?怎么走到这里来了。我不是在分析单元测试的问题吗?对了,我最初的问题是TDD,怎么一路跑到设计上来了?
TDD?设计?
你突然发觉自己对TDD的理解有一些偏差。TDD,并不代表不需要设计。读过很多书的你突然想起了Robert Martin那本著名的《敏捷软件开发》,上面有一个关于数据库访问的例子。那个例子里面,前后两个版本的差异正好就是考虑设计的结果。通常,在设计中考虑测试,会很容易找到设计中僵硬的部分,让程序更加灵活。再进一步,如果在开始动手之前,稍微进行一些设计,这些问题还是可能注意得到的。你突然觉得,正是因为TDD本身过于强调测试的价值所在,让你忽略软件开发中很重要的部分:设计。
思路一下子清楚起来,TDD其实不只是“红——绿——重构”,它还是与设计相关的:在动手之前,还是要有一定的设计,而且,在设计中要考虑测试的问题。终于解开了心中的困惑,现在的你,对于TDD有了一个新的认识,虽然这个认识不见得是什么终极真理,但至少是通过自己的思考得来的,这让你更加相信实践出真知的道理。
理清思路后,你更加坚信TDD本身的价值所在,也坚定了在日后开发中继续使用TDD的念头,当然,目光远大的你已经盯上了其它的敏捷实践。