本文是《Vue组件库工程探索与实践》系列文章第三篇,聊聊组件库单元测试和持续集成功能的实现。javascript
单元测试是软件工程领域的一个重要概念,指对软件中的最小可测试单元进行检查和验证,它是代码正确性验证的最重要的工具。单元测试也是组件库实现自动化测试与集成的基础。html
单元测试会封闭执行最小化单元的代码,使添加新功能和追踪问题更容易。对代码进行单元测试有不少好处:前端
前端小伙伴们对单元测试多多少少都有必定的了解,但真正有实践经验的并不太多。我想可能与业务项目工期紧张、需求变化比变脸还快、对单元测试的意义认识不够等方面因素有关。固然,也不是全部项目都须要单元测试。vue
不过,随着时间的推移,阅历的累积,或许有一天你会真正意识到它的价值,就像李宗盛的歌。java
对于组件库这种可复用的公共代码来讲,其对可靠性、可维护性的要求较普通业务类项目代码更高,引入单元测试是十分必要的。这里分享一下咱们在Vue组件库的单元测试方面的探索与实践。node
限于篇幅,本文重点谈Vue组件库的单元测试功能及实现,不会过多介绍单元测试基础知识。webpack
首先咱们须要明确,Vue组件库的单元测试,主要仍是针对其中的Vue组件。git
为了方便对 Vue 单文件组件进行测试,Vue.js 官方提供了测试工具库 Vue Test Utils
,它提供了一系列方法用于测试Vue组件。github
Vue Test Utils
经过把组件隔离挂载,模拟必要的输入 (prop、注入和用户事件) 和对输出 (渲染结果、触发的自定义事件) 的断言来测试 Vue 组件。被挂载的组件会返回到一个包裹器内,而包裹器会暴露不少封装、遍历和查询其内部的 Vue 组件实例的便捷的方法。此外,Vue Test Utils
还提供了模拟用户交互的相关方法。web
可见,Vue Test Utils
是 Vue 组件单元测试的必备工具,须要安装。
$ npm install --save-dev @vue/test-utils
复制代码
测试运行器 test runner
即运行测试的程序,也就是咱们一般所说的测试框架。Vue Test Utils
是与测试运行器无关的,主流的测试运行器都支持。
官方推荐两个测试运行器:Jest
和 mocha-webpack
。
Jest
是 Facebook 开源的一套 JavaScript
测试框架, 它自动集成了断言、JSDOM、覆盖率报告等几乎全部测试工具,功能至关强大。它所需的配置是最少的,不过须要一个可以将Vue单文件组件导入到测试中的预处理器。Vue.js
官方提供了 vue-jest
预处理器来处理最多见的单文件组件特性,但仍不是 vue-loader
所有的功能。
而 mocha-webpack
是知名前端测试框架 Mocha
与 webpack
的一个包裹器。下面这行命令就是它的大体工做原理:先对文件进行 webpack
编译,再用 Mocha
对编译后的文件进行测试。固然,其中还包含不少优化工做。
$ webpack test.js output.js && mocha output.js
复制代码
所以咱们可以经过 webpack + vue-loader
获得完整的Vue单文件组件支持。mocha-webpack
的配置比 Jest
复杂不少。
mocha-webpack
的2.0.0-beta.0
版支持webpack 4
为了得到完整的Vue单文件组件支持,咱们在 NutUI 2.0
项目中选择了 mocha-webpack
测试运行器。
Vue.js 官方的测试工具库 Vue Test Utils
依赖浏览器环境,而启动真实的浏览器是很是复杂的,由于涉及到不一样的平台和版本,兼容性与稳定性不易处理。从另外一个角度看,自动测试一般不须要浏览器的用户界面,使用无头浏览器(headless browsers
)就能知足需求。
无头浏览器是一种没有图形用户界面的网页浏览器,能够在相似于流行的 Web 浏览器的环境中提供对网页的自动控制,经过命令行界面或使用网络通讯来执行。它们能以与浏览器相同的方式渲染和理解 HTML,包括页面布局、颜色、字体选择、JavaScript 与 Ajax 的执行等等。一般用于 Web 的自动化测试等场景。
当下比较流行的无头浏览器有 JSDOM、Puppeteer、Selenium 等等,咱们的项目中选择了 JSDOM
在 Node 虚拟浏览器环境运行测试。
$ npm install --save-dev jsdom jsdom-global
复制代码
// 在测试的配置文件中
require('jsdom-global')()
复制代码
“断言”就是判断代码的实际执行结果与预期结果是否一致,若是不一致就抛出一个错误。全部的测试用例都应该包含至少一条断言。它是编写测试用例的关键。
好比下面这条断言,它的含义是调用 add(1,1)
的结果应该等于2。
expect(add(1,1)).to.be.equal(2);
复制代码
断言功能由断言库来实现。Jest
框架内置了断言库 expect
,而 Mocha
不包含断言库。因此选择使用 Mocha
框架的时候,咱们还须要额外安装一个断言库。
expect
断言风格(如上面的栗子)很接近天然语言,NutUI 2.x
项目的断言库选用的也是 expect
。除了 expect
,流行的断言库还有 chai
、assert
、should
等。
$ npm install --save-dev expect
复制代码
在测试的配置文件中引入 expect
,并把它挂到全局对象上,固然也能够在每一个测试文件中分别导入。
global.expect = require('expect')
复制代码
在肯定了测试运行器使用 mocha-webpack
,浏览器环境使用 JSDOM
,断言库使用 expect
以后,咱们就能够开始在组件库脚手架中进行测试工具的安装和配置了。
首先安装测试所需依赖。
$ npm install --save-dev @vue/test-utils mocha mocha-webpack@2.0.0-beta.0 expect jsdom jsdom-global
复制代码
而后,在项目根目录下新建 test/setup.js
目录及文件,用来设置测试所需的全局环境。咱们在该文件中引入 JSDOM
和 expect
。
require('jsdom-global')();
global.expect = require('expect');
复制代码
接着,在 package.json
文件中新增一个测试脚本。
{
"scripts": {
"test": "mocha-webpack --webpack-config webpack.test.conf.js --require test/setup.js src/packages/*/__test__/**.spec.js"
}
}
复制代码
--webpack-config
指定了测试使用的 webpack 配置文件 webpack.test.conf.js
。该文件与生产环境配置文件有些差别,下文会细说。--require
标识确保文件 test/setup.js
在测试以前运行,所以咱们能够在该文件中设置测试所需的全局环境。测试覆盖率是对测试彻底程度的度量,是由测试需求、测试用例的覆盖或已执行代码的覆盖表示的。
一个统计 JavaScript
单元测试覆盖率的知名工具是 istanbul
,它以土耳其最大城市伊斯坦布尔命名,由于土耳其地毯世界闻名,而地毯是用来覆盖的。
咱们来看下在 mocha-webpack
框架下,如何使用 istanbul
统计测试覆盖率。
首先,咱们须要安装 nyc
和 istanbul-instrumenter-loader
:
$ npm install --save-dev nyc istanbul-instrumenter-loader
复制代码
nyc
: istanbul
的命令行工具。istanbul-instrumenter-loader
: 使用钩子(hooks)包装代码以在代码执行时跟踪覆盖率的loader。接下来,修改 package.json
文件 scripts
字段下 test
脚本,同时增长 nyc
的相关配置项:
{
...
"scripts": {
"test": "cross-env NODE_ENV=test nyc --reporter=lcov --reporter=text mocha-webpack --webpack-config build/webpack.test.conf.js --require test/setup.js src/packages/*/__test__/**.spec.js"
...
},
"nyc": {
"include": [
"src/packages/**/*.vue"
],
"instrument": false,
"sourceMap": false
},
...
}
复制代码
test
脚本中 --reporter=lcov --reporter=text
是配置 nyc
同时输出lcov (lcov.info + html)
和文本形式的覆盖率报告。
而 scripts
字段下方 nyc
的配置项中:
include
用来指定被测试源文件的位置。nyc
的 instrument
和 sourceMap
选项,由于这些工做应该由 loader 负责。接下来须要把 istanbul-instrumenter-loader
加到 webpack 的配置文件中。上文提到,咱们给单元测试工做指定的 webpack 配置文件是 webpack.test.conf.js
,它与生产环境的配置文件有些差别,咱们先把生成环境的配置文件 webpack.prod.conf.js
导入,再把这些差别 merge 进去。
const path = require('path');
const prodConf = require('./webpack.prod.conf.js');
const merge = require('webpack-merge');
module.exports = merge(prodConf, {
module: {
rules: [
{
test: /\.(js|ts)/,
use: {
loader: 'istanbul-instrumenter-loader',
options: { esModules: true }
},
include: path.resolve(__dirname, '../src/packages/')
},
],
},
devtool: 'inline-cheap-module-source-map',
externals: [require('webpack-node-externals')()]
});
复制代码
js/ts
类型的文件新增了 loader: istanbul-instrumenter-loader
,要注意的是,该 loader 必须放在数组的第一个,以确保它最后一个应用。sourceMap
在 mocha-webpack
中必须经过内联方式获取,因此 devtool
选项推荐的值为 inline-cheap-module-source-map
。webpack-node-externals
外置全部的 NPM 依赖。至此,整个项目的自动化测试功能及覆盖率统计配置基本完成,咱们在 src/packages/
目录下的每一个组件的目录下新建一个__test__
目录,该目录下的单元测试文件以 .spec.js
做为扩展名。
准备好组件的单元测试文件以后,在终端执行 npm test
便可启动测试。测试的过程当中,终端会展现每一个测试用例的测试结果。
测试结束以后,终端会以文本形式展现出本次测试的覆盖率报告,同时 /coverage
目录下也会生成测试覆盖率报告文件(Icov.info+html)。
持续集成(Continuous Integration, CI)是一种软件开发实践,即每次代码的集成都经过自动化的构建(包括编译/发布/自动化测试)来验证,从而尽早的发现集成错误。也就是说,只要代码有变动,就自动运行构建和测试,确保符合预期后,再将新代码集成到主干。它的核心措施是,在代码集成到主干以前,必须经过自动化测试。
持续集成的意义在于:
Travis CI 是在线托管的 CI
服务,使用 Travis
来进行持续集成。它对于开源项目是免费的,支持绑定 Github 上面的项目。只要有新的代码,就会自动抓取。而后,提供一个运行环境,自动进行构建和测试,还支持部署到服务器。
咱们来看下 Travis CI
的基本用法。
首先,访问 Travis CI 官网并使用 Github 帐户登陆。 而后,点击其网站右上角的我的头像,网页会列出 Github 上咱们和咱们所在的组织的全部代码仓库。打开须要进行 CI
的仓库右侧的开关便可。
接下来,咱们须要在这个代码仓库的根目录放置一个名为 .travis.yml
的 Travis CI
配置文件。NutUI 2.x
项目的配置文件内容以下:
sudo: required
language: node_js
node_js:
- '8'
script:
- npm test
- npm run coveralls
复制代码
sudo: required
表示须要 sudo
权限。language: node_js
指定运行环境为 Node 。node_js
字段用来指定 Node 版本。script
字段用来指定构建或者测试的脚本。Travis
的运行流程包含两个阶段:install
(安装依赖)和 script
(执行脚本)。对于 Node 项目来讲,install
和script
阶段都有默认脚本,如不须要修改,能够省略不写。
install
的默认脚本是:npm install
。script
的默认脚本是:npm test
。Travis CI
还支持自动部署,但不是必须的。咱们的组件库没有用到,这里很少说。
配置完成以后,每次往 Github 的该仓库 push 代码,都会触发 CI
。登陆 Travis CI
网站能够看到结果。
咱们还能够从 Travis CI
网站获取一个关联该仓库 CI
结果的徽标,放在咱们项目的 README.md
文件中,这样即使不登陆 Travis CI
网站,咱们也能够经过该徽标知晓 CI
结果了。
查看 NutUI 的 README.md
文件,会发现除了上文提到的CI结果徽标,还有一个展现测试覆盖率的徽标。
这个徽标是经过 coveralls.io
获取的。 coveralls.io
提供测试覆盖率的追踪服务,咱们能够把测试覆盖率报告上报给 coveralls.io
,它会基于接收到的数据生成一个测试覆盖率徽标。
coveralls.io
支持 Github 上的项目,也能够与 Travis CI
集成。关于它的具体使用,限于篇幅,这里就不展开了,有兴趣的小伙伴能够阅读其官方文档。
好了,这篇文章先聊到这里。若是对具体实现细节感兴趣,能够查看 NutUI 2.x 项目的源码,也欢迎各位老铁Star,赠人Star,手有余香~