J.Timothy King写了一篇很棒的文章:“先写单元测试的12个好处”(Twelve Benefits of Writing Unit Tests First)。遗憾的是,他在文章最后说的话完全是画蛇添足。
然而,如果你不愿意改掉先写代码的老习惯,如果你觉得固执己见比设计优秀的软件更重要,好吧,我对你深表同情。
把你的怜悯用在不认同你的人身上,并不是推广你主张的最有效的方式。
看看T先生的例子吧。他从1980年代初开始怜悯傻瓜,但迄今为止,“愚蠢”在这个世界仍然是随处可见。
译者注:T先生(Mr. T)是一位美国演员。他在1980年的电视剧《The A-Team》里饰演B. A. Baracus这个角色,并因此一举成名。后来他还在1982年的电影《Rocky III》里扮演拳击手Clubber Lang。他总是留着标志性的非洲曼丁卡族武士的发型。2006年,他做了一档贴近现实社会的电视秀,节目名字叫“I Pity the Fool”(我同情傻瓜)。
J.Timothy King有点弄巧成拙了,因为关于单元测试的主张是很重要的。单元测试的普遍接受,已经成为过去5~7年里软件开发领域里最大的进步之一!
你是怎样解决一个软件问题的?在学校里老师教过你吗?你首先会做什么?你在开始解决问题的时候,会问,“我要写什么代码来解决这个问题呢?”但其实这是后面的问题。你最先要问的问题不是“我要写什么代码”,而是“我怎样才能确认我的方法解决了那个问题?”
在我们接受的教育里存在一个假设,就是我们已经知道如何去判断我们的解决方案是否奏效。这根本就不是问题。就比如下流行为,我们看到的时候也就知道了。关于代码需要去做什么事,我们相信也没必要在写代码之前去思考一下。这种信仰已经根深蒂固,对于大部分人来说,这是很难改变的!
J.Timothy King罗列了12个具体的方法,来帮助大家接受“测试先行”的观念(这种方法已经帮助他写出了更为出色的代码):
- 单元测试可以证明你的代码是能真正解决问题的
- 你可以获得一个底层模块的回归测试工具
- 你可以在不破坏现有功能的基础上持续改进设计
- 一边写单元测试,一边写实现代码,这种工作方式更有乐趣
- 它们可以用来真实地展示开发进度
- 单元测试可以用作为演示代码
- 它逼着你在写代码之前做好计划
- 它降低Bug修复的成本
- 单元测试甚至比代码审查的效果还要好
- 它实际上为程序员消除了工作上的障碍
- 单元测试促成更好的设计
- 它比不写单元测试而直接写代码的效率更高
上面这个列表里,即使你只认同3~4个——根据我的经验,至少一半以上是正确的——对于软件开发者来说也是一个巨大的进步。关于单元测试的重要性,我绝对没有不同意见。恰恰相反,我越来越相信,单元测试是如此之重要,以致于它应该成为第一类的语言构建(像类、方法、事件等一样)。
然而,我觉得“测试先行”(或者说“测试驱动”)的倡导者太专注在他们自己的立场上,有点急于求成了。要求开发人员一夜之间彻底改变他们开发软件的方式是很过分的。特别是,有些开发人员还从来没有写过单元测试。对于任何软件开发组织来说,如果他们还没有把单元测试采纳为每一个软件项目的标准方法,那我也不认为他们具备了采用“测试驱动”开发方法的条件。
对“测试驱动”的过度推崇和膜拜,可能使得软件开发人员对单元测试的整个概念都产生怀疑和厌恶。
要真是那样,就很可惜了!因为关于软件测试,测总比不测好。我们对随机测试(Ad-hoctesting)的概念很熟悉,其实单元测试也就是一种更为正式一点的随机测试,难道不是吗?我觉得Fowler有段话说得非常好:
译者注:在软件测试中,除了根据测试样例和测试说明书进行测试之外,还需要进行随机测试,主要是根据测试者的经验对软件进行功能和性能方面的抽查。
译者注:Martin Fowler是世界级软件开发大师,在面向对象分析设计、UML、模式、XP和重构等领域都有卓越贡献,现为著名软件开发咨询公司ThoughtWorks的首席科学家。他的多部著作,如《分析模式》、《UML精粹》、《企业应用架构模式》、《重构:改善既有代码的设计》等,都已经成为脍炙人口的经典。
你想把某些信息打印到屏幕或输出给调试器的任何时候,你都应该把它改写成一个单元测试。
我希望开发人员能够认识到单元测试的价值。我力劝他们在编写功能代码的时候,也养成编写结构化测试代码的习惯。观念改变一点点,可能最终会促成更大的飞跃,就比如测试驱动开发——但是,在开始跑之前,你必须先学会爬!