本文首发于 Vue 应用单元测试的策略与实践 06 - 如何落地的几点建议 | 吕立青的博客javascript
欢迎关注知乎专栏 —— 前端的逆袭(凡可 JavaScript,终将 JavaScript。)前端
// Given
一个须要在团队中推行测试策略的Tech Lead👨💻
// When
当他🚶阅读本文的Vue应用测试策略落地部分
// Then
他可以在团队中按部就班地推行测试策略,
他可以找到单元测试的反馈机制,追求技术卓越
复制代码
谈到如何推动单元测试的落地,首先得要有一个开始。不少公司都在推行 OKRs 或者 KPI 机制,而技术部门如何衡量技术性的绩效呢?说实话,咱们都知道技术类绩效其实很差用某些指标来衡量,但不少时候老板们都会道听途说以为软件质量特别重要,而后你们开始用测试覆盖率来做为考核标准,先随便定个数吧,就 80% 不错。但咱们都知道,哪怕 100% 测试覆盖率也没法保证软件质量,盲目追求高覆盖率反而会物极必反出现问题,最终致使你们之后对单元测试痛恨至极。java
但正由于有了这样一个开始的契机,你们才开始有意识提升软件质量。并且你们最开始都会以为“单元测试是个好东西”,承认快速开发的同时,质量也很重要,这就是我所说的政治正确。既然都有了 OKR 的支持,那么也就意味着,公司容许你们学习单元测试可能付出的成本,投入了成本固然就意味着潜在的收益。那么如何快速得到收益,就成了下一个话题。react
前文也说过,有些同窗就会在内心嘀咕:为了达到“保障质量”的目的,不必定得经过测试呀,就算须要测试,也不必定得经过单元测试。这话在最开始的时候,确实是对的,谁都想得到好处以后才能放心投入进去,否则那些网络骗子们为何最开始总会给点回报看成诱饵呢?因此根据测试奖杯🏆,**使用静态类型系统和 linter **就是咱们最初的诱饵,ESLint 可以捕获拼写或语法之类的基本错误,而且大多数状况下 ESLint 每每都能经过 --fix
进行自动修复(配合 VSCode/WebStrom 插件食用更佳)。git
这一段时间,也就是养成一种反馈回路,即暗示-惯常行为-奖励(via: 《习惯的力量》),等到你们都习惯了“出现 Lint 错误就自动修复”的自动反馈以后,便也就是离不开这一套自动化的工做方式。并且在这一阶段,咱们为此付出的成本基本为 0,最开始也不必使用最严格的 ESLint 规则(airbnb/javascript: JavaScript Style Guide),按部就班就好。github
前文在讲测试原则的时候也提到过单一职责原则(SRP),不少同窗在遗留代码之上写单元测试的时候,表示特别痛苦。“这都是些啥呀,输入/输出不明确,还各类反作用,一个函数作了七、8件事情,一个类承担五、6种角色。”因此呢,这时候咱们要明白 Vue 和 Vuex 诞生的背景是什么,理解它们各自要解决的问题是什么。只有规范好各自的职责,才可以把 UI 和数据流清晰得隔离开来。只有这样,咱们做为 vuex store 的使用者,才会变得简单,而不仅是把 vuex action 当成一个 API 的简单 wrapper,全部数据处理逻辑所有都仍是放在 UI 组件里面。vuex
**什么是架构,其实架构就是把代码放到该放的地方。**不写代码的架构师们固然就不会知道,也不会知道代码写烂以后,该如何去补测试。那可能就不仅是一种“补测试就像吃剩饭”的感受了,那只能是一种在不明排泄物之上堆💩的体验。编程
再多说一下 Vue 组件自己,我一直以为 template 相比于 jsx 来讲,很大的一个问题就是不利于重构,即抽取组件。满屏的 this.xxx
就好像一个无敌的局部 global 对象同样,处处都能用,也就致使处处都有反作用,从而根本没法方便得抽取 function 或者放回 Vuex store。json
因此说,只有当咱们正确地使用 Vue 和 Vuex 以后,才可以为以后编写单元测试提供良好的基础。固然,这不是目的,哪怕不写单元测试,也应该利用好前端数据流对于代码的合理安放,遵循必定的原则就能享受该有的好处。我只是想声明,哪些抱怨单元测试难写的人,不是由于单元测试难写,而是你的实现代码实在太挫。
// production code
const computeTotalAmount = (products) => {
return products.reduce((total, product) => total + product.price, 0);
}
// testing code
it('should return summed up total amount 1000 when there are three products priced 200, 300, 500', () => {
// given - 准备数据
const products = [
{ name: 'nike', price: 200 },
{ name: 'adidas', price: 300 },
{ name: 'lining', price: 500 },
]
// when - 调用被测函数
const result = computeTotalAmount(products)
// then - 断言结果
expect(result).toBe(1000)
})
复制代码
这个测试的例子虽小,但五脏俱全。就是一个最简单的 输入/输出 function,这就是最方便测试的地方,也最具测试价值,由于这都是最重要的业务数据逻辑。想想你的 Vue 项目中哪些地方会有这样的纯函数呢?
固然就是 Vuex 的 mutation。因此当咱们开始推行前端单元测试的时候,不要从 UI 组件开始,而是从 JavaScript 开始,从最简单的 function 开始,遵循这个 given-when-then 的结构,可让团队写出比较清晰的测试结构。这样的单元测试,既易于阅读,也易于编写。
最大的好处,实际上是减小学习成本。大多数团队成员其实都是从模仿开始,只有单元测试易于编写,那么你们才会愿意跟着开始尝试写。而最开始的那份单元测试,必定得是写得标准的,得是易于阅读的,从而才是易于模仿的。反过来讲,模仿,这也是“破窗理论”之因此流行的缘由。
只要你们开始动手写单元测试,就成功了最难的 50%,接下来就须要你们坚持下来。借鉴于《游戏改变世界》这本书中所提到的理论支持,咱们须要为你们创造反馈,创造更满意的工做和更有把握的成功。
精心设计的游戏工做让人以为更有生产力,由于它感受起来更真实:反馈来得又强又快,影响明显而生动。对不少不喜欢本身的平常工做、以为它没有什么直接影响的人而言,游戏里的工做提供了真正的奖励和知足感。
那么,咱们该如何为团队创造游戏里打怪升级般的测试开发体验呢?顺便咱们能够回答一下,该如何按部就班提高项目单元测试覆盖率这个问题。
👆上图的道理咱们都明白,哪怕天天只进步 1%,那么一年 365 天的效果也是无比非凡的。咱们能够给项目添加一个单元测试覆盖率提高的hook,即每次push都会检查并更新测试覆盖率的阈值,每次提交都不能少于上一次提交,这样咱们就能够持续进步、持续改进,持续提升测试覆盖率啦。
平时的工做平常,咱们还会有一个电视做为 CI Monitor,因此咱们能够把团队项目的测试覆盖率放上去,每次提交以后测试覆盖率都会高一点点,给每位同窗一个即时的反馈,鼓励你们坚持下去。
参考 Koleok/jest-coverage-ratchet: Uses jest coverage output to raise acceptable coverage threshold to current coverage 配置 jest 的 coverageReporters:
# jest.config.js
coverageReporters: [
"json-summary", "json", "lcov", "text", "clover"
],
coverageThreshold: require('./package.json').jest.coverageThreshold
复制代码
而后配置 Git hook,加到 prepush
里面自动更新 测试覆盖率阈值。
"coverage": "lerna run coverage && git add **/package.json && git diff-index --quiet HEAD || git commit -m \"test(unit): update coverage threshold CASABASEA-1246\" --no-verify",
...
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
"post-commit": "git update-index --again",
"pre-commit": "lint-staged",
"pre-push": "yarn lint && yarn test && yarn coverage"
}
复制代码
在 XP 极限编程提到的反馈环中咱们能够看出,除告终对编程之外,单元测试是咱们开发者最好的反馈工具。
既然单元测试应该由开发者,在开发软件的同时编写对应的单元测试。它应该是内建的,而不是后补的:即在编写实现的同时完成单元测试,而不是写完代码再一次性补足。测试先行,这正是 TDD(测试驱动开发)的作法。使用 TDD 开发方法是获得可靠单元测试的惟一途径。
前文提到测试很难补,其实补出来的测试几乎不可能完整覆盖咱们对重构和质量的要求。TDD 和单元测试是全有或全无:不作 TDD,难以获得好的单元测试;TDD 是得到可靠的单元测试的的惟一途径。除此以外别无捷径,想抛开 TDD 而得到一个好的单元测试是迷思,难以成功。
TDD(测试驱动开发)的步骤以下,可以时刻给予开发者反馈,从而坚持下去:
就我本身而言,写这篇文章的同时,我也在团队中推行 Vue 单元测试的落地,与此同时也尝试了 Snapshot Testing 快照测试、Storybook 组件化测试、使用 Cypress 作 E2E 的 UI 测试等等。只能说,这过程并无想象中的那么容易,质疑、埋怨、叫苦的声音源源不断,但每当只要有一位同窗说上一句“我好像体会到写测试的好处了”,“这样写,实现代码都变得很清晰了”,哪怕只有一位,那也就足够了。
道不一样不相为谋,前途茫茫,技术卓越之路艰且险,与君共勉。
## 单元测试基础
## Vue 单元测试
find()
方法与选择器## Vuex 单元测试
Redux-like
架构## Vue 应用测试策略
## Vue 单元测试的落地
本文是【草稿】React 应用单元测试策略的姊妹篇。除此以外,还有两个缘由:1. 上次在FCC社区讲TDD的时候说过单元测试的部分太干不适合讲,而是更适合写成博客文章做为技术参考;2. 公司内部已全线使用Vue技术栈做为产品开发的前端框架,而单元测试却因周期较紧而不得已暂且搁置。