最近在搭建一个项目的前端开发环境,准备趁此把一些没用过的东西尝试下,比如:单元测试。
使用 vue-cli
可以直接生成一个包含 unit
、 e2e
测试的开发环境,不过还是需要去了解其中的组织结构、配置和模块的使用等。
没有一点相关经验,先把 vue-cli
生成后的 test/unit
目录拿到自己的项目中。
test
目录结构:
- test
- unit
- specs
- .eslintrc
- index.js
- karma.conf.js
之后在 package.json
中找到 karma
相关的模块。
webpack
。karma
和 webpack
的桥梁。不经过 webpack
编译命令是文件是无法独立运行的, karma
需要了解你的 webpack
配置,决定如何处理你的测试文件。phantomjs
在 karma
中的启动器,由此引出了 phantomjs
。 PhantomJS 是一个没有界面的 “浏览器” ,内置了 JavaScript API,支持各种Web标准:DOM 处理、CSS 选择器、JSON、Canvas 和 SVG 等。在查找相关资料时,也发现了其他的常规浏览器 launcher
,比如:Chrome、Firefox、Safari、IE 等,以应对不同浏览器或多浏览器的测试需求。见 BrowsersKarma
插件,生成文件的 sourcemap
。mocha
。karma
中使用 sinon-chai
断言库的插件,前置依赖有 sinon-chai
、 sinon
、 chai
…:confused: 其中要使用 karma-phantomjs-launcher
,需要先安装 PhantomJS
,通过 phantomjs-prebuilt
安装。
看到这一大堆依赖,感觉面前又是一个不亚于 Webpack 的技术栈。之所以去了解每个模块的用处,就是为了在学习的时候直插心脏,忽略那些不重要的模块。
以上来说,Karma 是基本的运行器,需要了解其配置和使用。测试框架 Mocha 和断言库 sinon-chai 类似于开发中使用的 Lodash,提供一系列用于测试的工具函数。剩下的按示例集成就好。
整合一条命令。
npm i -D karma karma-webpack phantomjs-prebuilt karma-phantomjs-launcher karma-sourcemap-loader mocha karma-mocha sinon chai sinon-chai karma-sinon-chai karma-spec-reporter karma-coverage
PhantomJS 安装比较慢,也可以去其 官网下载 ,并手动 配置环境变量 。
安装好了,先跑一下看看是否安装正确,到 package.json
的 scripts
中注册一个命令: "unit": "karma start test/unit/karma.conf.js --single-run"
,然后运行。
npm run unit
然后不出意料的报错了,只是少装了一个模块 isparta-loader
,是一个代码覆盖工具,继续安装后运行OK。
karma.conf.js 文件内容分为两部分。
module.exports
以上是对 Webpack 配置的处理,像 webpack.dev.conf
和 webpack.prod.conf
那样,在不同的环境里使用不同的配置。后一部分就是对 Karma 的配置了。
module.exports = function (config){
config.set({
// 要启动的测试浏览器
browsers: ['PhantomJS'],
// 测试框架
frameworks: ['mocha', 'sinon-chai'],
// 测试报告处理
reporters: ['spec', 'coverage'],
// 要测试的目标文件
files: ['./index.js'],
// 忽略的文件
exclude: [],
// 预处理文件
preprocessors: {
'./index.js': ['webpack', 'sourcemap']
},
// webpack
webpack: webpackConfig,
webpackMiddleware: {
noInfo: true
},
// Coverage options
coverageReporter: {
dir: './coverage',
reporters: [
{ type: 'lcov', subdir: '.' },
{ type: 'text-summary' }
]
},
// true: 自动运行测试并退出
// false: 监控文件持续测试
singleRun: true,
// 以下是 vue-cli 没有生成的一些配置
// 文件匹配的起始路径
// basePath: '',
// 服务器端口
// port: 9876,
// 输出着色
// colors: true,
// 日志级别
// LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
// logLevel: config.LOG_INFO,
// 监控文件更改
// autoWatch: true,
// 超时处理,6s内没有捕获浏览器将终止进程
// captureTimeout: 6000
})
}
其中对于测试文件入口有点难以理解,仅仅是一个脚本文件,而不是路径匹配,也就是配置文件同级的那个 index.js
,只有 5 行代码。
Function.prototype.bind = require('function-bind')
const testsContext = require.context('./specs', true, /\.spec$/)
testsContext.keys().forEach(testsContext)
const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/)
srcContext.keys().forEach(srcContext)
看起来如果使用了高版本的 NodeJs 第一行代码是可以去掉了。
testsContext
匹配的是 specs
目录,里面是存放的是测试用例;srcContext
匹配的是 src
目录,从正则上看是除了 main.js
以外的所有文件。也就是说,也可以通过脚本文件这种方式设置匹配的目标文件。
现在看起来一切妥当了,可以开始写测试用例了。
把以上步骤又重复了一遍,集成到了一个自己写的 Demo 项目中,然后运行测试。
什么鬼,找不到 less
变量。
为了验证不是配置问题,我在 vue-cli 生成项目的组件中使用 less 写了个样式,运行测试出现了一样的问题。
最后找到了这条 issue 。
翻译了半天,感觉是匹配文件的问题。
const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/)
原来的正则会匹配除了 main.js
以外的所有文件,所以样式文件也会被匹配上。使用 less 时一般只有一个变量文件,然后从一个 less 出口文件中解析,而单元测试本身做的工作是单文件测试,单个 less 文件肯定是找不到变量的。
不过样式本身是不会对逻辑产生影响的,可以不参与测试,干脆直接锁定目标文件后缀,也就是 vue 组件。
修改如下:
const srcContext = require.context('../../src', true, /\.vue$/)
刚翻过一座山,又遇到一条河。
看起来是因为 API 不兼容,PhantomJS 中还没有集成 Promise。
为了避免相似的问题,索性把 launcher 换掉了,用 karma-chrome-launcher
。
安装后,更改 Karma 配置中的 browsers
属性值为 ['Chrome']
,测试运行成功。
有一些青色的 LOG,第一条使用 Vue 的应该都已经熟悉了,是浏览器控制台输出的 LOG,所以其他的也是浏览器的日志了。
第 1、3、4 条 LOG 是有一个指令没有找到,第 2 条是关于路由的。指令和路由的引入是在项目入口的 js 文件内,可以预知如果我使用了其他类别的 Vue 插件也会报出 ERROR。
还是有问题要解决啊!:unamused:
初次接触测试框架和断言,对于组件的测试用例也还在摸索中。
从例子上看,大概思路如下:
import Vue from 'vue'
import SearchView from 'src/components/SearchView'
describe('SearchView.vue', () => {
it('Input is normal ', () => {
const vm = new Vue({
el: document.createElement('div'),
render: (h) => h(SearchView)
})
vm.key = '曾经的你'
vm.$nextTick(() => {
expect(vm.$el.querySelector('.m-key').textContent).to.equal('曾经的你')
})
})
})
实际的项目中,针对复杂的逻辑或者异步操作,测试一定不会这么简单。:sweat_smile:
下一步准备找一些 Vue 的开源项目,学习一下其中的测试用例写法。
End!
转载:https://imys.net/20161110/vue-unit-test-start.html?utm_source=tuicool&utm_medium=referral