开发中的单元测试及 Code Review

2020年4月11日 13:50

单元测试

在软件开发过程中,有两个极端,一个是完全不写单元测试,另一个是测试驱动开发。

完全不写单元测试,并不是说功能上线完全不测试,这是不可能的,最起码开发人员会在一些关键环节打一些日志或者断点跟踪一下关键过程,提交前会自己跑几个测试用例。不写单元测试是指提交到仓库的代码没有显式编写单元测试,这还是有点让人不安。尤其是涉及到原有功能的改动,自己本地的测试是否能够完全覆盖,这个时候不能太过自信。

另一种比较极端的情况是测试驱动开发,一个类比的例子就是建筑工人会在砌墙的时候,会通过打垂线之类的方式,保证后续垒砖的时候能够保持水平。这里的垂线及平行线就相当于单测,后续的代码编写一定要保证符合单测的要求。不过这种开发方式在实际应用中有点困难。

在实际生产中,设计先行,功能开发结束后补充单测,或者完成一部分功能后就补充一部分单测,这种方式应该是比较常用的,当然也不排除有的公司不要求写单测,但这必定会给测试团队增大工作难度。我对客户端开发、native SDK 开发、后端开发都有接触,就实际经历而言,客户端、native 开发还没见过有人在代码中显式编写单元测试(也可能是我待过的团队不够多),后端开发人员写单元测试的较多。不过这也可能跟工作特点有关,对客户端来说,面向的是实际的用户,很多用户的行为完全超出你的想象,开发团队很少有精力对功能做出完全的测试覆盖;对于 native 开发及后端开发,面向的用户是客户端(或后端),这些行为的复杂度低了几个数量级,写单测的难度就会小很多。我在实际开发中会用到 Python,动态类型语言很多地方都是不确定的,所以这种情况下单测显得尤为重要,写了单测都不能保证功能完全没问题,更不用说完全不写单测了。

除了保证功能在大部分情况下的正常行为,写单元测试最大的好处我认为就是,能够在开发中时刻提醒自己写出容易测试的代码,不然补充单测的过程简直就是灾难,这也算是一种反向驱动的机制。容易测试的代码,很重要的特点就是:功能单一,复杂度低。过于复杂的代码,除了增大后期维护的难度,在 code review 以及代码交接时都会遇到问题。

团队强制 code review

每次提交代码需要经过团队内部 code review 才能合并,无论开发需求是大是小,强制 code review 有很多好处,比如这会限制你每次只提交一部分代码,避免一次性提交大量代码让人无从看起,以及后期排查问题时精准定位;另一点就是别人会跳出你的定势思维,发现你无法发现的问题,好处多多。

无论是编写单元测试还是强制团队 review 代码,除了公司基础开发环境 CI/CD 的建设,还需要推行这种团队文化,初期可能会影响一点开发效率,但是从提高功能稳定性以及形成良好编码习惯的角度来说,这种投入十分值得。