Vue 应用单元测试的策略与实践 01 - 前言和目标

前言

本文主要尝试解决三个问题:

  1. 在 TDD 做完 Tasking 列完实例化数据之后,完全没有 UT 基础不知道该怎么写单元测试?
  2. 在 Vue 应用的单元测试中,对 UI 组件和 vuex store 等测试的区别有何不同?颗粒度该细到什么程度?
  3. Vue 项目中测试收益如何最大化,如何配置高性价比的测试策略,即什么地方最该花力气测试,什么地方又可以暂且放一放?
  4. 在 Vue 项目中如何推动整个团队循序渐进地采取单元测试策略?逐步提高代码质量和测试覆盖率?

不谈论的包括:

  • ATT 验收测试 或 E2E 端到端测试,这个是我想进一步探索的话题,特别是在 TDD 的语境下。#322
  • 为什么要 TDD?但是我会讲为什么要 UT 单元测试。测试和 TDD 是两码事,而光是自动化测试的好处就已经足够多,但是如何做到更好的自动化和持续集成,那就需要 TDD 来指引方向。
  • Snapshot Testing 快照测试,其实我是很认可快照这种形式,但需要改进其工作流,至少结合 Image Snapshot 和 Storybook 等工具,甚至更应该放到 CI 上去。#311

下面我就来结合具体场景,进一步实例化这些问题,举几个 🌰:

1. 在 TDD 做完 Tasking 列完实例化数据之后,完全没有 UT 基础不知道该怎么写单元测试?

// Given
一个完全没有 UT 基础的新人 🚶
// When
当他 🚶 阅读和练习本文的 Jest 的部分
// Then
他能够把 Given/When/Then 的套路学会
他能够学会 Jest 的基本用法,包括测试 suite 和断言等语法
他能够学会 Jest 中测试异步的几种方式

2. 在 Vue 应用的单元测试中,对 UI 组件和 vuex store 等测试的区别有何不同?颗粒度该细到什么程度?

// Given
一个有基本的 UT 知识但没写过 Vue 测试的新人 🚶
// When
当他 🚶 阅读和练习本文的 Vue 单元测试的部分
// Then
当然,他能够学会 Vue 组件在测试当中的几种渲染方式
他能够学会 UI 组件的分类,特别是交互行为的测试方式
他能够对 Vuex 概念的理解更加深入,且知道 `Redux-like` 架构的好处
他能够合理测试 vuex store 的 mutation 和 getter 中的业务逻辑
他能够测试组件如何正确 dispatch action 以及 action 中如何做异步操作

3. Vue 项目中测试收益如何最大化,如何配置高性价比的测试策略,即什么地方到底该花力气测试,什么地方又可以暂且放一放?

// Given
一个具备 UT 基础但找不到着力点的求索之徒 🐒
// When
当他 🚶 阅读本文的 Vue 应用测试策略部分
// Then
他能够找到测试的重点,重新燃起对 UT 的热情 🔥
他能够在项目背景下合理配置单元测试的测试策略

于是乎,这就是本系列文章的大纲,先放出来给大家一个对于 Vue 应用单元测试的全局观:

## 单元测试基础

### 为什么选择 Jest

### Jest 的基本用法

### 该如何测试异步代码?

### 单元测试与自动化的意义

## Vue 单元测试

### Vue 组件的渲染方式

### Wrapper `find()` 方法与选择器

### UI 组件交互行为的测试

## Vuex 单元测试

### CQRS 与 `Redux-like` 架构

### 如何对 Vuex 进行单元测试

### Vue 组件和 Vuex store 的交互

## Vue 应用测试策略

### 单元测试的特点及其位置

### 单元测试的关注点

### 应用测试的测试策略

😯 哦豁,正文终于开始……


为什么要有单元测试?

引用好友鲜明的观点就是:写不好是能力问题,不写则是态度问题。单元测试客观上可以让开发者的工作更高效,Vue 应用的单元测试是一定要的。

单元测试的上下文

谈任何东西都一定要有个上下文。你的论述不能是「因为单元测试有这些好处,所以我们要做单元测试」,而应该是「不做单元测试我们会遇到什么问题」,这样才能回答「为什么要写单元测试」的问题。那么我们谈论单元测试的上下文是什么呢?不做单元测试我们会遇到什么问题呢?

agile

上图为一个产品从 idea 分析、设计、开发、测试到交付并获取市场反馈的过程。

单元测试的上下文就是存在于「敏捷」当中。敏捷为的是更快地交付有价值的可工作的软件。为此,它有一个指标来度量这个「更快」,那就是 lead time,它度量的是一个 idea 从提出被验证,到最终上生产环境面对用户的时间。显然,这个时间越短,软件获得反馈的时间就越短,对价值的验证就越快发生。

单元测试的意义

这个结论对我们写不写单元测试有什么影响呢?答案是,不写单元测试,你就快不起来。为啥呢?因为每次发布,你都要投入人力来进行手工测试;因为没有测试,你倾向于不敢随意重构,这又导致代码逐渐腐化,复杂度使得你的开发速度降低。

那么在这个上下文中来谈要不要单元测试,我们就可以很有根据了,而不是“开发爽了就用,不爽就不用”这样含糊的答案:

  • 如果你说我的业务部门不需要频繁上线,并且我有足够的人力来覆盖手工测试,那你可以不用单元测试
  • 如果你说我不在意代码腐化,并且我也不做重构,那你可以不用单元测试
  • 如果你说我不在意代码质量,好几个没有测试保护的 if-else 裸奔也不在话下,脑不好还做什么程序员,那你可以不用单元测试
  • 如果你说我确有快速部署的需求,但我们不 care 质量问题,出回归问题就修,那你可以不用单元测试

除此之外,你就需要写单元测试。如果你想随时整理重构代码,那么你需要写单元测试;如果你想有自动化的测试套件来帮你快速验证提交的完整性,那么你需要写单元测试。

单元测试与自动化的关系

综上,我们用来谈论单元测试的「透镜」是什么呢?一言以蔽之,两点:反馈速度自动化

自动化回答的是要不要自动化的单元测试这个问题。测试是重构的唯一保障,也就是说,没有测试,基本上就没法重构代码(重构指的是 不改变软件可观测行为的前提下改善代码内部设计或实现 ),基本上就只能看着代码腐化。那么,基本上只要你的系统需要持续发展,你就需要单元测试。

反馈速度回答的是要不要 TDD、测试先行还是后补这个问题。答案是,需要 TDD,最好先行,因为可以提高反馈速度,缩短反馈周期,与此同时减少不必要的浪费。

再考虑到以下两大事实:人员会流动,应用会变大。人员一定会流动,需求一定会增加,直至再也没有一个人能够了解应用的所有功能,那时对应用做出修改的成本将变得很高。因此,意图依赖人、依赖手工的方式来应对响应力的挑战首先是低效的,从时间维度上来讲也是不可能的。因此,为了服务于“高响应力”这个目标,随时重构整理代码是必须的,这就需要我们有一套自动化的测试套件,它能帮我们提供快速反馈,做质量的守卫者。唯解决了人工、质量的这一环,开发效率才能稳步提升,团队和企业的高响应力才可能达到。

至此,回答了「为什么我们需要写单元测试」的问题。下面让我们来谈谈如何写好 JavaScript 代码和 Vue 应用框架的单元测试。

如何选择一个测试框架?

众所周知,JavaScript 世界里最不缺的就是轮子,测试框架也是如此。其实这里的子标题就是为什么选择 Jest?有时候安于现状,只不过是因为我们没有见过理想的模样。只有当我们见过更好的世界和更好的测试框架,才会惊呼“原来世界是这样美好呀!我怎么都没有想到呢?”

引自技术雷达:Jest 是一个“零配置”的前端测试工具,具有诸如模拟和代码覆盖之类的开箱即用特性,主要用于 React 和其他 JavaScript 框架。
我们团队对采用 JEST 做前端测试的结果非常满意。它提供了一种“零配置”的开发体验,并具备诸多开箱即用的功能,比如 Mock 和代码覆盖率等。你不仅可以将此测试框架应用于 React.js 应用程序,也可以应用于其他 JavaScript 框架。Jest 经常被炒作的功能之一是用户界面的快照测试。快照测试可以作为测试金字塔上层一个很好的补充,但请记住,单元测试仍然是坚实的基础。

一个好的测试框架,Jest 的几大好处可以涵盖为:

  • Fast 天下武功,唯快不破。确实很快,虽然实测下来跟 Mocha 新版本还是慢了些,以后找个机会再测一次。
  • Opinionated 不需要你做出选择和配置,就能提供所有的东西,比如 Mock(干掉 Sinon)、Test Runner(干掉 Karma)、Matcher(干掉 Chai)、Test Coverage(内置 istanbul)
  • Watch Mode 守护模式。非常注重开发者体验,能够在编码的时候帮助我们快速获得测试结果的反馈。
  • Snapshot Testing 快照测试。这是值得争议的一点,前文也提到过会专门开个 issue 来讨论,在此不再赘述。

最后,总结一下 Jest

Jest 作为一个测试框架,其最大的特点就在于它是一个非常有效的解决方案,不需要与其他测试库交互来执行它的工作。与此同时 Jest 非常注重开发者体验,这一点也是特别值得欣赏,现在市面上关注开发者(“人”)体验的开发框架和工具实在不多,而 Jest Watch 模式的核心就在于快速获得反馈,虽然我没在命令行使用而是 WebStorm 但亦可以与之结合。

ps: 除此之外,还有很多开发者体验亦值得细细品味与发现,特别是 Jest 本身来自 Facebook 的工程化支持也是特别棒的,这个讲述如何开发 Jest 的官方视频值得一看:Building High-Quality JavaScript Tools

未完待续……

## 单元测试基础

  • ### 为什么选择 Jest
  • ### Jest 的基本用法
  • ### 该如何测试异步代码?
  • ### 单元测试与自动化的意义

## Vue 单元测试

  • ### Vue 组件的渲染方式
  • ### Wrapper find() 方法与选择器
  • ### UI 组件交互行为的测试

## Vuex 单元测试

  • ### CQRS 与 Redux-like 架构
  • ### 如何对 Vuex 进行单元测试
  • ### Vue 组件和 Vuex store 的交互

## Vue 应用测试策略

  • ### 单元测试的特点及其位置
  • ### 单元测试的关注点
  • ### 应用测试的测试策略