年纪大了,腿脚不利索,拄着拐杖走路,走的稳不说,还能预防跌倒。程序员
但若是真的跌倒了呢?安全
跌倒后有没有人敢扶?扶起来还能不能走?若是能走,走得还能不能像之前那样快?若是不能走,是否是要去医院?数据结构
没了拐杖,产生了灾难性的骨牌效应。单元测试
单元测试之于开发人员,至关于老人的拐杖,离开拐杖,也能走,但就是深一脚浅一脚,并且还有随时跌倒的危险,跌倒以后还会产生一系列的问题,搞的人焦头烂额。测试
在没有单元测试支撑的状况下写代码,你不会知道代码里面有没有逻辑BUG,是否符合预期,不能发现编码过程当中引入的错误,更不能发现设计和需求中存在的问题。编码
我曾经所在的一家公司,开发人员是不写测试的,他测试本身代码的方法,是写完以后运行一下,点点看有没有问题,效率低下容易漏测不说,还很业余,简直侮辱软件工程师这个高大上的职业(看我鄙视的眼神)。spa
假设你写了一个服务,每写一个方法你都写单元测试将方法中的路径全覆盖掉,如异常,if-else, switch语句等,刚准备提交,忽然接到通知,需求变了,你不得不改动编码逻辑,这个时候怎么办呢?首先要跑一遍单元测试,确保你当前功能的测试全跑通,而后分析需求,按照要求对相应的代码进行了修改,以后,修改或增长单元测试对改动代码进行覆盖,你点下了开始按钮,看着全部测试都打了绿色的对勾(✔),你从容淡定的提交了代码,拿起菜刀,哦不,端起水杯,跟分析师说:改好了!你看下是否是酱婶儿的?设计
咱们一块儿来看看刚才发生了什么。调试
首先,由于编写了全路径覆盖的测试单元,因此你不怕需求变动,也就是说,单元测试对于重构或者需求变动来讲,能让咱们对编写的代码更有信心。接口
其次,能够预期遇到的错误,是冒泡交给上层逻辑仍是在方法体内消化掉,都在你的掌握之中。即使咱们编码或者写测试的过程当中没有发现这些异常,有想不周全的地方,后面遇到了这个异常,也能够修改测试将其覆盖到测试里面。咱们对本身写的程序有了全面的了然于胸的掌控。
比较完备的研发团队,通常都会配置测试部门,在接到需求文档以后编写测试计划,开发人员结合需求文档,阅读测试计划,能够很快理解项目的流程和操做场景。甚至有经验的开发能够直接依据测试计划使用TDD模式快速实现。
但大多数开发仍是使用的编写逻辑边单测的模式,因此这里说一下在业务支撑型项目的开发中,咱们写单元测试的原则,并简单介绍一下经常使用方法。
首先要说到的,是项目和数据依赖问题,这个问题分析起来,首先要问你这个测试方法的测试目标是什么?是测试代码的业务逻辑仍是测试项目依赖的元数据。若是是前者,咱们彻底能够编写面向业务逻辑的测试单元,数据部分则用Mock解决。但若是是后者,你须要确保在测试、生产等环境里项目依赖的元数据存在才能正常运行,那么,能够专门编写测试单元来检查当前环境下是否存在该元数据的定义及存在预期的数据定义。这个例子中,一个是检查代码逻辑,一个是确保项目正常运行,是两个不一样目标的测试单元,因此,一个要用到Mock,一个须要检查环境。
而后咱们说外部接口和项目依赖。这个问题比较常见。对于所依赖的外部接口,咱们必须假定它是不稳定的,编码时要作好降级准备(如接口无响应,返回值错误等状况的处理),给用户一个友好的反馈。那么怎么测试呢?
一样,须要分别写两个测试单元,一个用来检查调用外部接口的方法的返回值,是否符合外部接口的期待;另外一个测试单元用Mock模拟外部接口返回的各类结果来检查咱们的后续逻辑。
为何不直接调用外部接口测试呢?那是别人家程序员的任务啦!
标准的团队都会配置一个测试小组,开发任务完成后,提交测试。测试组的同事使用各类姿式虐待咱们的项目,将找到的BUG提交给咱们进行修复。这个时候,咱们第一件要作的事情仍是编写单元测试,去复现这个BUG,而后再去修改代码,直到BUG再也不出现。这也是对测试同事的尊重,保证你再次提交代码后,这个BUG不会重复出现。
这句话听起来有点反人类。但事实上,编写单元测试不但不会形成项目延期,反而会使咱们的工做目标更明确,从而使编码工做更高效,最终每每会提早完成目标。
为何会这样呢?由于目标很明确,你会少写不少臆想的代码逻辑,再加上这些猜想着写出来的代码还可能存在BUG,后果就是你花了很长时间在调试修改一段没必要要的逻辑。
随着迭代的逻辑愈来愈复杂,由于有着测试的支撑,每次修改和功能的增长,变得轻量而敏捷,优雅而神秘。
可能有同事以为“重构”这个词太过恐怖,认为只要是重构,就是对程序结构、数据结构的推翻重来。但那些注重成长的程序员非但不会认为重构恐怖,还会将重构做为成长路上的最好的伙伴。
重构的频率,最好是每次提交代码前,对本身的代码进行一次自审。问本身这段代码是否过于繁琐?有没有更简洁的方法?它的可读性好很差?可维护性怎么样?若是代码量比较大,或者你正在审查本身多个里程碑的代码,可能还会问本身关于设计原则和模式方面的问题。
重构的间隔太长,会演变成严重的技术债务,而这些技术债务的偿还,才是本节开头所说的,对程序结构、数据结构都会有很大的改动,相较于每日自审重构,复杂度、数据风险以及开发成本都会成为使人头疼的问题。尤为是当你去重构“前任”留下的代码时,那心情,非常酸爽。因此,为了避免让咱们的“后来者”酸爽,请坚持每次提交前的自我审查和重构,固然,前提是你写了单元测试。
一个事实是,用户的需求随着业务须要一直在变化,因此咱们的程序也一直在迭代,要想保证咱们每次的迭代又快又稳定(或者调整现有功能,或者增长新的功能),咱们必须给本身一个安全措施,这就是单元测试。
因此,不要怕重构,每次提交前审查代码->重构代码->执行单元测试,应该成为咱们每次提交前固定的工做流程。
单元测试和重构,成长路上的好伙伴。
研发中心 张鹏
2019-11-29