写在前面
网上写单测的文章太多了,要么是介绍工具(jest、mocha、chai 等)的,要么是照本宣科介绍什么是单测的。看过之后总是觉得无法指导实际开发,不够接地气,于是尝试着总结了此篇文档,希望能够补上这块缺失。所以本篇文章里不会出现单测的基本概念与单测工具的介绍,有的只是指导实践的一些方法论。
为什么要求单测覆盖率?
首先,「覆盖率」不是目的,只是达到目的的手段,我们希望:
- 通过「单测」唤起同学们对代码质量的意识;
- 通过「单侧覆盖率」这个指标来保证和推进方案的落地;
- 通过「写单测」来提高同学们的代码质量(为什么能提高?请看下面「重新认识单测」部分);
所以,「覆盖率」绝不是目的,虽然覆盖率不能简单的等同于代码质量,但是如果想持续提高覆盖率,并把覆盖率维持在一个较高水平,是一定会触及到更深层次的改变的。 至于如何制定覆盖率的标准,这个建议由项目自己制定一个长期计划,此计划务必做到持续提高和维持高水平,可参考下文「怎么写好单测」部分。
什么不是单测?
比起什么是单测,让我们先来看看什么不是单测,也许会给我们更多启发:
需要访问网络的测试不是单元测试 需要访问文件系统的测试不是单元测试 --- 修改代码的艺术
纯函数,副作用,幂等,函数式编程……如果你的脑海里出现了这些词汇,恭喜你,你已经上道了。
写单测有什么好处?
- 安全放心:这是显而易见的,相信你一定有过不少上线时心里没谱甚至胆战心惊的经历吧。
- 大胆重构:就算这个系统是你从零搭建的,你重构的时候也绝对会犯同样的错误。
- 解释性:测试用例就是你最好的说明文档,甚至相当于 demo。
以上是直观的,大家都懂的,下面说些容易被忽视的
- 提升设计能力:如果你认真对待单测,那么它会强迫你写出可维护性更好的代码。如果你发现代码不容易甚至不能写单测,那么八成是代码设计的问题。当你思考并重构了这部分代码时,相信你会觉得付出的精力和时间都是值得的,你再写出「可测试性不好」的代码的可能性就越来越小了。另外,据说 85% 的缺陷都在代码设计阶段产生,而发现bug的阶段越靠后,耗费成本就越高,指数级别的增高。
- 提升全面思考能力:单测经常会写边界 case,久而久之这种思路会形成惯性,以后在写代码时思路会非常清晰,思维缜密、面面俱到也会成为习惯。
- 提升代码质量:这步已经是水到渠成的了,是上面几条所结的果,无需赘述。
- 节省时间:别喷我,我只是个搬运工,请看从头到脚说单测——谈有效的单元测试里提到的《单元测试的艺术》那个例子
什么是好的单测?
- 正确、清晰、简洁。实践中单元测试不光测试代码的正确性,还能够帮助其他开发者理解代码逻辑,理解如何使⽤相关的类或者函数(可以当做接⼝或函数的使⽤⽰例了,省的写使⽤⽂档和 demo 了),所以要求单测写的清晰,简洁,有⾮常好的可读性。
- 完整性,也是必需的,单测应该有很⾼的覆盖率,把可能的输⼊输出场景都考虑到。
- 健壮性,是最容易被忽略的一项。当被测试的类或者函数被修改内部实现或者添加功能时,⼀个好的单测应该完全不需要被修改或者只有极少的修改。⽐如⼀个排序函数的单测实现是完全稳定的,它不应该跟着不同的排序算法⽽变化。
- 有个好名字,让⼈⼀看就知道是做什么测试,如果名字不能说明问题也要加上完整的注释。⽐如 testSortNumbers_withDuplicated, 意味SortNumbers函数的单元测试来验证有重复数字的情况。
- 逻辑简单,尽量避免使⽤命令式编程(Imperative Programming)引⼊条件判断,循环等复杂逻辑。否则很可能会给单元测试⾃⾝带来不少bugs,这样就需要写单元测试的单元测试了……⼀句话单元测试不要引⼊复杂的逻辑,最好是不要引⼊逻辑。
- 完备⽽不重复。同样的测试场景,或者同类型的测试输⼊不要写多个单元测试,找⼀个有代表性的场景输⼊就可以了。
怎么写好单测?
以下只是一些理论,请结合实际进行改良
战略四步走
- 会写,项目里有工程,可以写单测,人人可写即可
- 写好,对代码是否可测有判断力,知道如何写出「可测试性好」的代码
- 重构,随着单测覆盖率的提升,一些代码自然被重构,开始出现良性循环
- 常态,写新代码时,已经想好了单测怎么写,二者同时进行,形成常态
战术四要素
- 核心代码优先、重点覆盖单测,如公共函数,公共组件等。此时要求「精」,处于战略 1、2 阶段,要注意修炼内功
- 设计好目录结构。如常量(无需测试)单独一个文件,并统一命名,方便 ignore;UI 组件与数据处理等逻辑分为不同文件,不要耦合;公共组件放在一个目录下,方便统计覆盖率等
- 函数式编程思维,尽最大可能降低函数的副作用,最典型的就是要把 window,localStorage 等全局变量作为参数传入,而不是在函数里直接访问并操作
- 把副作用控制在一定范围内,副作用是很难避免的,那么就把它们统一收敛起来,比如操作 localStorage,只允许通过一个二次封装的函数来触发,类似于 redux、vuex 等状态管理机制的思想
参考资料
- 浅谈前端单元测试
- 为什么谈前端单元测试
- 前端单元测试实践
- 从头到脚说单测——谈有效的单元测试
- 干货 | 测试扁平化之必备神器:好的单元测试
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!