coding

[翻译]写单元测试的12个好处

前言:

这是一篇国外开发者写的文章,主要介绍了测试先行的12点好处。一位台湾的开发者把它翻译成了繁体,为了方便大陆开发者阅读,我将繁体翻译成了简体,分享出来。江边望海做开发多年,对开发不写测试深有感触。真的有时候不是不写,而是压根就没有想过要写,一部分原因是眼界狭窄造成的。我建议开发者可以经历以下两点,可能会对测试先行有更深的理解:

1.尝试做半年的测试工作,去探索测试驱动开发的方式和方法;
2.尝试在Github.com上注册帐号,并fork别人的代码后Pull Request自己修改的代码,参与到与他人的协作中去。


以下是翻译原文:

「写单元测试的好处是什么?」

这个问题非常难以回答。通常只能得出「只有写了才知道」这种含糊不清的答案。

我最近找到Tim King在2006年的文章,非常完整的回答了这个问题。

看过之后觉得获益良多,翻译出來和大家分享。


为什么工程师会讨厌写单元测试?为什么他们会拒绝先写单元测试?不用解释了,那些接口我全听过。我知道真正的原因为何。

大部份的工程师根本没认真试过测试先行。不然就是当下的环境不支持他们写,导致他们不知道自己在干嘛。前者的情況居多。最后他们就找接口:「我们没时间写单元测试」、「单元测试不能完全保证程序代码品质」。这是在替自己的窘境找理由,而不是真的觉得不写比较好。有趣的是,当这种人直接在你面前开发,你常会看到他开发得很不顺,进度常常在开倒车。目睹这种事满有趣的。但他依旧不会收回原本的看法、依旧不愿意先写测试。这种坚持根本有害。

Kent Beck在《Test Driven Development By Example》书中提到,测试先行有3个步骤:

1. Red:写个能表达你打算如何使用那段code的测试,还有你期待它做什么。这个测试会失败。很多界面会用红色信息来表示它。
2. Green:写出足够的code來让那个测试成功,但別多写。如果你想写更多code,像是检查某些错误的話,那就先另写一個测试表达它。当下只要写刚好够的code去通过测试即可。
3. Refactor:把多余的code清理一下,然后改善整体设计。之后再跑一次测试,確保沒弄坏什么地方。

重复这些步骤直到功能做完。这个流程超级简单。为什么工程师会畏惧它?因为这会逼他们从根本上改变开发习惯。

我们认为自己在写code前不需要先去思考,这些code到底要做什么。

你如何解決一个软件问题?学校是怎么教的呢?第一步怎么走?你大概只想着如何解決问题本身。你心想:「我要写哪些code来实现出解決方案?」其实你不应该先想「我要写哪些code」,你要先想「我要怎样才能确定问题已经被解決了?」

我們直觉认为一段code的正确与否,只要执行一次就知道了,超明显的,何必写那种根本废话的测试?就是这种根深蒂固的想法,导致大部份的人改不了开发习惯。

成功跨过那道鸿沟的人,可以感受到下列几项好处。我全部体会过。不用完全信我,你自己试试看就知道了。

1. 单元测试保证你的code真的能动

这会让bug减少。当然,单元测试不能取代系统测试和验收测试。但单元测试能补足他们的短处。

2. 你会得到一组低层的regression-test suite

这让你随时可以回头去检查有否哪些坏掉、bug在哪。很多团队会每天把整组测试跑一遍。這让你在把程序交给品管部门之前,可以很轻松的把bug抓出來。

3. 让你改善系统设计的時候,不怕弄坏系统

其实就是测试先行3步骤的第3步。通常测试先行写出來的code不太需要重构。我看过很多超糟糕的系统,就像精神病患一样,根本无法搞定。如果有准备好单元测试,你就可以对系统里面最难搞的部份做出有效的重构。

4. 写测试会让coding更好玩

你会先搞懂自己的code要做什么。然后再让它完成任务。就算系统还沒全做完,你还是能看到code真的动起來,而且真的沒出错。你会得到一种「我完成了!」的感觉。每分钟都会不断感受到喔。只要试试测试先行,你就会整个人high起來、对自己的作品感到骄傲、被激励去完成更多事情。

5. 他们可靠地展现目前进度

你不用为了等整个系统组装起来而多等一个月。在系统完成之前你就能展示进度了。不但能说自己写了code,还能真的跑给別人看。传统开发有件事搞错了。「完成」不等于你写了code然后丟出去。「完成」应该是你的code能在系统里跑,而且沒bug。写测试会让你更接近这点。

6. 单元测试是一种使用范例

我们都碰到过那种不知道怎么用的library。通常我們会先去找范例程序代码。使用范例可算是一种文件。但公司內部的code通常不會有范例可看。所以只好慢慢试、在系统內东找西找了。因为那个同事可能已经离职了,想问他都沒办法。单元测试可以当作一种文件。当你不知道Foo类怎么用的时候,去看一下单元测试怎么写的即可。

7. 测试先行会强迫你写code前先做规划

先写测试会逼你在动手开发前把必须完成的事和整体设计思想过一遍。不但让你更专注,还能让设计更漂亮。

8. 先写测试能减少bug的成本

越早发现bug越容易修。之后出现的bug通常是改了好几个地方才出现的,
导致很难抓出哪里导致了bug。一开始先找出bug在哪,然後要重新回想這段code是怎么写的,因为可能是几个月前写的。最后才终于弄懂,搞出一套解法。只要能减少抓bug以及修好bug的时间,几乎都算大賺。如果在成品交給品管部门或是顾客之前,我们只花几天就找出bug,通常算是很幸运。哪儿有花几分钟就找出bug呢?测试先行就能做到这点。

9. 它比代码检查的效果好

有人说事前代码检查比事后测试系统更好,因为成本比较低。在系统完成之后才测试系统,要修好bug可说是麻烦多了。越早发现bug,就越简单、越便宜、越好搞定。代码检查的好处就在这:只花几天就能抓出bug,不需要等几個月。但是测试先行成本更低。只要几分钟就抓出bug,连几天都不用。

10. 几乎解決了「开发者瓶颈」(coder’s block)

不知道下一行写什么吗?就跟「作家瓶颈」(writer’s block)一样,开发者瓶颈很可能是个大问题。测试先行有系统处理开发上关于结构的部份,让你能专心在需要创造的部份。你可能会卡在下段code不知道怎么测、该怎么通过测试,但你永远不会因为下一步卡住。通常会有完全相反的结果:你很想在累倒之前休息一下,但因为清楚看到前面的录了,所以根本不想停下來。

11. 单元测试让设计更棒

测试一小块code会強迫你定义清楚那段code负责什么。如果测起来很简单,就表示它的责任很明确,cohesion很高。如果一段code能被单元测试,那就表示它很容易就能放进系统之中,就跟它很容易放进测试之中一样。它跟相关的code只具有loose coupling 。 High cohesion与loose coupling代表了出色、好维护的设计。容易测试的code也很容易维护。

12. 写测试会让开发速度更快

不写单元测试也许会让开发速度更快,但无法保证code真的能跑。开发上会花一堆时间在事后修bug。测试先行会消除这类的浪费,从一开始就做对、让bug更好修。

就算好处这么多,很多工程师还是继续维持他们的老样子。如果你在组织里极度重视流程,你跟他们一部份人会起冲突。我只能祝你好运。记住一件事,人们不会因为一个东西听起来不错就买账。他们只有在极度渴望、超想得到手来品尝时才会买账。希望以上几点可以帮助你说服他们。

不过,如果你是前者,也就是那种顽固的工程师,不在乎好的软件设计,只在乎坚持己见…。嗯,我觉得你还真可怜。

翻译原文来自于:http://blog.turn.tw/?p=2821

发表评论

电子邮件地址不会被公开。 必填项已用*标注