我们为什么要写单元测试

Published: Creative Commons Licence

  • Categories:

1. 引言

关于单元测试想必诸位程序员都不陌生,这里就不再赘述了。

但据我所知,很多程序员是很少去主动写单元测试的,理由也很多,比如时间紧任务重来不及,不如直接Code and run来得快;还有就是除了看起来正规一些,好像写了单元测试也并没有什么实际的好处……久而久之就养成了不写UT的习惯。

话说我为什么这么清楚呢?当然是因为我之前就是这些人的一员啦。不过最近我开始在工作中大量地写单元测试,并体会到了它的好处,有了一点更深入的理解。

本文就记录下来我关于单元测试的一些感悟,比较务虚偏理论一点,以后有机会再续写实战篇吧。

2. 为什么要写单元测试

那么,我们为什么要写单元测试?

我的观点是:为了提高生产力,节约宝贵的时间(然后实现准点下班自由)。

如果你想要成为一个开发速度又快Bug又少的优秀程序员,那么单元测试一定是帮助你实现目标的一大利器。

接下来我从如下几点来论述单元测试是如何实现上述目标的。

2.1 思考更周全

软件开发时最忌讳思考不周全就匆忙开始写代码,后期发现问题后再修修补补,可能还会引入新的问题,严重者甚至要把最初的代码推翻重来,非常非常浪费时间。

单元测试则可以尽早督促你进行严谨的思考,因为你在写UT时一定是要去想要覆盖到哪些case的,这个思考的过程就是一次很好的查漏补缺:各种边界条件的考虑是否完善,逻辑判断是否严谨,非法输入和意外情况的处理是否合理等等。

有些人提倡测试驱动开发TDD,主张要先写测试代码,再写功能代码,这一点我还没有做到,不过即使是在写完功能代码后再去写UT,也是很有帮助的。

另外,单元测试也可以倒逼你写出结构更加清晰的代码,毕竟给混乱的代码写测试是很痛苦的事情。

2.2 易于验证

想象如下的场景:

你接到一个需求,首先需要由上游传入一个值作为输入,再去调用一个外部团队提供的API,再根据他们的处理结果来进行下一步的逻辑。

这个需求比较简单,你花了一小会就写完了全部的代码,但是如何验证自己的代码是正确的呢?

如果没有单元测试,就会遇到重重困难:

  • 需要把代码部署到测试环境进行功能测试来验证效果,每次修改代码重新部署的时间也都够你喝一杯咖啡了。
  • 依赖他人进度,如果他们的功能开发比你慢就会阻塞你的测试。
  • 可能会遇到环境问题,比如外部团队的测试服务挂了,查询API不可用,你就抓瞎了。
  • 需要了解如何构造出来想要的测试数据,如何针对性的覆盖到不同的case,而且某些特殊case不好构造(苦力活)。

但是如果你用了单元测试:

  • 本机直接跑UT,几秒就可以完成
  • 直接Mock外部依赖,不会被他人进度影响
  • 不会真正调用外部服务,不需要担心环境稳定性
  • 随心Mock各种case

2.3 无惧变更

变更是程序员永恒的主题,而UT的一次编写,长期受益特性,会让你对待变更多一份从容。

每当你需要对原来的代码进行修改时,如何保证修改后的代码原有的功能还是正确的呢?

如果没有写UT,则是需要把之前的case重新覆盖一遍,也就是回归测试。

这时候如果之前有写过比较高质量的UT(不是简单为了凑覆盖率的那种)的话,你就可以在修改完代码之后,马上跑一下之前的UT,这可以帮你迅速发现问题,要么是代码逻辑有误,要么是UT之前的假设不成立了,此时则需要调整UT。

很多程序员非常畏惧修改原有代码,生怕改出bug,这当然无可厚非,但这很容易造成代码质量的长期下降。如果有了高质量UT的辅助,你就可以更加大胆的进行重构和优化,而不用担心破坏原有的逻辑。

3. 结语

单元测试是一把利剑,使用得当可以有效提高生产力,节约宝贵的时间。但是却被很多人给忽略了,或者认可单元测试的价值,但是被前期投入给吓退了,不愿意在一开始投入额外的精力去做这些东西,但是最后反而陷入了测试困难的泥潭,多耗费掉了更多的时间和精力。

认真写单元测试,也许在最开始是额外的投入,但是在后期却会给你带来持续无穷的好处,节约更多的时间和精力,我们需要想清楚这一点道理之后,做出正确的选择。