最近在搭建一个项目的前端开发环境,准备趁此把一些没用过的东西尝试下,比如:单元测试。

使用 vue-cli 可以直接生成一个包含 unit 、 e2e 测试的开发环境,不过还是需要去了解其中的组织结构、配置和模块的使用等。

准备

没有一点相关经验,先把 vue-cli 生成后的 test/unit 目录拿到自己的项目中。

test 目录结构:

- test
- unit
- specs
- .eslintrc
- index.js
- karma.conf.js

之后在 package.json 中找到 karma 相关的模块。

  • karma 一个 JavaScript 测试运行器,其在测试中的作用相当于开发构建中使用的 webpack 。
  • karma-webpack 连接 karma 和 webpack 的桥梁。不经过 webpack 编译命令是文件是无法独立运行的, karma 需要了解你的 webpack 配置,决定如何处理你的测试文件。
  • karma-phantomjs-launcher 是 phantomjs 在 karma 中的启动器,由此引出了 phantomjs。 PhantomJS 是一个没有界面的 “浏览器” ,内置了 JavaScript API,支持各种Web标准:DOM 处理、CSS 选择器、JSON、Canvas 和 SVG 等。在查找相关资料时,也发现了其他的常规浏览器 launcher ,比如:Chrome、Firefox、Safari、IE 等,以应对不同浏览器或多浏览器的测试需求。见 Browsers
  • karma-sourcemap-loader Karma 插件,生成文件的 sourcemap 。
  • karma-mocha 让你在 karma 中使用 Mocha 测试框架的插件,使用时还需要安装前置依赖 mocha 。
  • karma-sinon-chai 让你在 karma 中使用 sinon-chai 断言库的插件,前置依赖有 sinon-chai 、 sinon 、 chai …:confused:
  • karma-spec-reporter 用于将测试结果显示到控制台。
  • karma-coverage 生成代码覆盖率。

其中要使用 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:

测试用例

初次接触测试框架和断言,对于组件的测试用例也还在摸索中。

从例子上看,大概思路如下:

  1. 引入一个组件;
  2. 创建一个用于测试的 Vue 实例,然后组件挂上去;
  3. 对实例进行模拟操作,然后断言期望值。
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

Logo

前往低代码交流专区

更多推荐