Vue单元测试真的没那么难(上)

268 阅读5分钟

一、为什么要做单元测试

试想下这样的场景,你写了一个公共的组件,团队里有多个项目依赖它;某一天你发现了一个bug,改完之后仅仅验证了该bug的功能,或许你根本没有时间验证是否影响了其它的地方,这个时候你提交了,并且知会多个项目更新组件。 不幸的是当大家更新之后,发现你改的bug引发了其它的问题,这个时候你肯定很想骂人~

领导知道之后,让你要确保后续组件的质量,你会怎么做呢?

  • 自己多做测试,但是由于组件的场景复杂,每次修改都要验证所有功能,简直浪费时间,估计你不太愿意~

  • 交给测试同学,但是测试同学也会提出以上问题,也不会为了你改的一个小bug或者小功能就全量测试~

  • 交给单元测试,执行npm run test,简直太酷了,接了一杯水回来发现,测试通过了~

你领导看后,肯定让你选择方案三吧。

既然领导都发话了,接下来你不得不去调研如何对Vue单文件组件进行单元测试了。

二、Vue Test Utils

通过查资料,你知道了Vue官方提供了Vue Test Utils这个工具库辅助你对单文件组价进行单元测试。

先看下Vue Test Utils是干吗的?

Vue Test Utils 会将单文件组件隔离挂载,然后模拟必要的输入 (prop、注入和用户事件) 和 对输出 (渲染结果、触发的自定义事件) 的断言来测试 Vue 组件。

被挂载的组件会返回到一个包裹器内,而包裹器会暴露很多封装、遍历和查询其内部的 Vue 组件实例的便捷的方法。

我们想一下,要实现单文件的挂载至少需要哪些基本条件?

  • 需要挂载的DOM(可以是浏览器环境的DOM或者运行在Node上的虚拟浏览器环境的jsDom),由于浏览器环境比较复杂,我们选择jsDom;

  • 需要先将单文件组件进行编译,这样jsDom才能正常运行;

  • Vue。

有了以上三个条件,Vue Test Utils就可以将单文件组件生成HTML和JavaScript逻辑代码了。

三、选择一个测试运行器

测试运行器是执行测试集的程序。主流的JavaScript测试运行器比较多,且Vue Test Utils都支持。Vue Test Utils是与测试运行器无关的。

那我们该如何从众多测试运行器选择呢?需要关注以下几点:

  • 测试运行器给我们提供的功能集合是否足够强大
  • 性能
  • 对单文件组价预编译的支持

Vue Test Utils推荐以下两个测试运行器

  • Jest是功能最全的测试运行器。它需要的配置是最少的,默认安装了JSDOM,内置断言命令行的用户体验非常好。 不过需要一个将Vue单文件组件预处理器,这样Jest才可以处理。Vue Test Utils为我们提供了vue-jest预处理器来处理最常见的单文件组件特性,注意不是100%的vue-loader.

  • mocha-webpack是一个webpack + Mocha的包裹器。同时包含了更顺畅的接口和侦听模式。这些设置的好处是我们可以通过webpack+vue-loader得到完整的单文件组件支持,但是需要很多配置。

这里我们选择的测试运行器是Jest;

四、使用Vue test Utils和Jest单元测试的原理

通过以上介绍,我们大致了解到使用Vue test Utils和Jest对Vue单文件组件进行单元测试的流程大概如下图所示:

Vue单文件组件单元测试原理 (1).png

五、搭建单元测试环境

那我们的环境要依赖哪些库呢?

  • Jest
  • vue-jest
  • vue test utils
  • babel-jest(因为我们需要将ES6以上转成ES5)

1、Jest @vue/test-utils

对Vue2项目推荐以下版本,可以直接运行起来

npm i -D @vue/test-utils@1.3.0 jest@24.9.0

配置文件

{
  "scripts": {
    "test": "jest"
  }
}

2、Vue-jest

vue-jest是用来处理单文件组件的

npm i -D vue-jest@4.0.1

配置文件

{
  // ...
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      // 告诉 Jest 处理 `*.vue` 文件
      "vue"
    ],
    "transform": {
      //`vue-jest` 处理 `*.vue` 文件
      ".*\\.(vue)$": "vue-jest"
    }
  }
}

3、babel-jest

尽管最新版本的 Node 已经支持绝大多数的 ES2015 特性,你可能仍然想要在你的测试中使用 ES modules 语法和 stage-x 的特性。为此我们需要安装 babel-jest:

npm i -D babel-jest@24.9.0

配置如下:

{
transform: { 
    "^.+\\.js$": "<rootDir>/node_modules/babel-jest"
  }
}

4、 babel-bridge

如果你的Babel版本高于7还需安装 babel-bridge

npm install --save-dev babel-core@^7.0.0-bridge.0 

5、处理 webpack 别名

如果你在 webpack 中配置了别名解析,比如把 @ 设置为 /src 的别名,那么你也需要用 moduleNameMapper 选项为 Jest 增加一个匹配配置:

{
  // ...
  "jest": {
    // ...
    // 支持源代码中相同的 `@` -> `src` 别名
    "moduleNameMapper": {
      "^@/(.*)$": "<rootDir>/src/$1"
    }
  }
}

6、完整的jest.conf.js的配置如下:

// ./test/unit/jest.conf.js
const path = require('path');
module.exports = {
  rootDir: path.resolve(__dirname, '../../'), // 类似 webpack.context
  "collectCoverage": true,
  moduleFileExtensions: [ // 类似 webpack.resolve.extensions
    'js',
    'json',
    'vue',
  ],
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1', // 类似 webpack.resolve.alias
  },
  transform: { // 类似 webpack.module.rules
    '^.+\\.js$': '<rootDir>/node_modules/babel-jest',
    // '.*\\.(vue)$': '<rootDir>/node_modules/vue-jest',
    ".*\\.(vue)$": '<rootDir>/node_modules/vue-jest',
  },
  setupFiles: ['<rootDir>/test/unit/setup'], // 类似 webpack.entry
  coverageDirectory: '<rootDir>/test/unit/coverage', // 类似 webpack.output
  collectCoverageFrom: [ // 类似 webpack 的 rule.include
    'src/components/__test__/*.{js}',
    '!src/main.js',
    '!src/router/index.js',
    '!**/node_modules/**',
  ],
  transformIgnorePatterns: ['/node_modules/']
};

目录结构如下:

image.png

  • setup.js入口文件
import Vue from 'vue'
Vue.config.productionTip = false;

这样单元测试的配置文件就完成了~

7、npm run test

"scripts": {
    "test": "jest --config test/unit/jest.conf.js --coverage"
 }

六、总结

环境配置好之后,命令行npm run test之后我们就可以看到测试结果,这样就回答了开头领导的如何保证组件的质量问题。至于如何写单元测试用例,将会在下一篇讲解~

image.png