为什么很多程序员不喜欢写单元测试?

业界良心。。。。

点击打开链接https://segmentfault.com/q/1010000002415710

点击打开链接http://www.zcfy.cc/article/423


我认为这和懒惰与否没有关系,测试不是必须要写的,有人说:雇主不是为测试而付钱给我的(大意),这话的意思是如果客观条件不允许(比如时间紧张)或者没必要(比如目标代码你闭着眼睛都能写得很好)等情况下,测试不写也就不写了,没什么大不了。

如果你觉得自己“懒得写测试”,那么你必然有“犯懒”的理由吧?时间紧或没必要,你占了哪一条?

如果哪条都不沾,那或许是你不懂如何写测试——我指的不是技术层面上的“懂”,而是说如何让测试行之有效又不过度耗费你的精力——这就涉及到测试能带给我们些什么好处了。

对于程序员个体而言,测试最大的意义在于“建立和维持对代码的自信心”,这一点大致可分为两个层面:

  1. 从无到有的时候。如果你对要写的代码无比熟练,挥手即来,那么测试对你的意义微乎其微(此处假定代码的编写和维护都是你一个人,不牵扯协作开发者。并且就算有牵扯,测试的必要性也要视乎你们的协作方式,这个后面再说)。可如果你对要写的东西很陌生,脑袋里一团浆糊的时候,测试就可以变成你的“引路人”。简单地说,就是把复杂的大问题拆分成简单的小问题,然后用测试描述每一个小问题的输入输出,接着失败 => 代码实现 => 成功,如此循环往复,最终完成了整个解决方案。
    显然,不写测试也可以这么做(指拆分复杂问题的方法论),但是测试会有一些好处:

    • 每一个测试只对一个问题单元负责,哪里不通过哪里有问题,这有助于把复杂逻辑解构成若干简单的模块化的代码。等到重构的时候你就知道这有什么好处了。没有构造良好的测试,没人愿意重构。这对于代码的维护是很有帮助的,除非你是一锤子项目,那就无所谓了。
    • 因为测试先于代码编写(其实就是 TDD),所以对于接口的设计往往是先于内部实现完成的。这是一种很好地代码设计习惯,然而虽然人人都知道但大多数人总是做不到。测试则会间接的“逼迫”你先考虑接口设计,再关注具体实现,若你的接口设计有问题,通过先写测试很容易就能察觉到,避免写一大堆代码之后才发现这么写不合适。
  2. 从有到优的时候。刚才提到重构,除了维护代码需要重构,修补 Bug 或是增加新的业务逻辑也算是重构的一部分(不太严格的说)。测试本身就是对业务逻辑的实例化描述,你的测试能否覆盖到业务实际的范围取决于你对业务本身的了解程度有多深,不过反过来就算你有遗漏或者理解上的偏差也没关系,因为那些正确的测试已经保证了你实现的正确的部分。接下来对于错误(bug)你只需要修正有问题的测试或者补充没有覆盖到的逻辑;而对于新增加的业务也是一样的道理,扩充测试用例即可。当然最后一步是让都 pass。如果你测试写得好——我是说语义良好,那么它几乎就可以拿来做需求文档了。回头 PM 说你那儿那儿做得不对,你可以搬出测试给他/她逐条讲解,很容易就能知道你们之间的误差在哪里。
    除此之外就是针对代码质量的重构了,没有测试的时候最头疼的问题就是不敢随便对代码动刀子,因为你没有可靠的质量保障,有了测试就好多了(不能保障百分之百不会出岔子,毕竟测试也是人写的)。这方面就懒得多说了,自己经历几次就能体会。

总而言之一句话,对于个体而言,测试就是你对业务逻辑的理解在“纸面”上的体现,另外它可以促使你提高代码的质量,提高代码设计的水准。不过总的来说还是“锦上添花”而不是“雪中送炭”,不写测试的项目多了去了,也不见得就都会死掉。写不写测试,一则视客观条件,二则视主观要求,我的态度是不强求。至于那些说写测试降低效率的,纯属扯淡。我就这么说吧:

如果你觉得写了测试对自己没有什么帮助反而降低了开发效率,那你就别写了——因为你不会写测试(还是的,非技术层面的“不会”,而是理解层面的)。

再把眼界放宽些,如果你不只是一个个体,你或许维护着一个全世界很多人都在使用(或将来可能会使用)的开源项目,那么我的建议是:必须写测试!

这种情况下,测试不只是写给你自己看的,甚至都不只是写给你的团队成员看的,它更大的意义是写给“外人”看或者用的。有人说“我们会出文档啊”,nonono,文档是给“消费者”看的,作为一个开源项目,你总是有两类“客户”。一类是拿来用的消费者,另一类则是改进改进让它变得更好的贡献者;后者有很多都是从前者演变过来的。

当你作为一个贡献者参与进来的时候文档对你没多大帮助,因为你的目标不只是会用,你还要知道它到底是怎么工作的,要如何才能改动它以适应更多的要求。这个时候测试就像指南针,撰写良好的测试就好像一个对项目本身了如指掌的大管家,一步一步手把手的指导你这个项目是怎样从无到有一直发展到今天的。没有测试?那你就抱着源代码一行一行抠去吧。而且事情往往是这样的:测试良好的项目,其代码本身也很清晰,干净,易于阅读和理解;反之,测试糟糕甚或是没有测试的项目,代码往往如同一团乱麻一般,除了作者自己任谁看了都会头大如斗——哦,对了,就算是原作者,放上三个月不碰回过头来还能认出自己写得啥不?


你可以不写测试,只要你理解了我上面所说的种种情况并能够做出合适的决定,但是不写测试绝对不应该和“懒惰”划上等号。恰恰相反,有的时候我接到一个需求,我还就是“懒得”想实现的细节,索性先从写测试开始一步一步抽丝剥茧,最后不知不觉的也就写完了。这其实反映了测试恰恰是为“懒人”设计的编写代码的方法,前提是你知道如何正确的编写的测试。

现在大部分的测试教程都有一个通病,那就是用了大量的无意义的测试来举例讲解。这么做可以理解,毕竟教程的作者又不知道你的实际情况,为了浅显易懂起见,自然还是那些无意义的测试更容易看明白。我得承认真正学会写测试是需要时间来练习的,有些东西真是只可意会不可言传。对于初涉测试的程序员来说,那些教程里的无意义的例子的确容易给人一种错觉:如果实际工作中也要这么写测试的话实在是太啰嗦太繁琐了!没错,一开始是这样的。一你得坚持练习,二你得找对方法;测试是为“聪明的懒人”准备的玩具。

推荐两个东西,一个是 Gary Bernhardt 录制的一系列视频,大量的讲解了实际项目中的测试理论和技巧,都是干货没有无意义的东西,但是有难度,要反复多看多体会:https://www.destroyallsoftware.com/screencasts/catalog

还有一个是来自于现实世界中一个非常有名的例子,一群人利用测试和重构挽救了一个差点不可救药的经典项目 Redmine,之后他们为这次大规模的重构写了一本书:Refactoring Redmine,满满的都是经验值啊。



阅读更多

没有更多推荐了,返回首页