王红元coderwhy新课线上前端系统班
在使⽤vue-cli创建项⽬的时候,会提⽰要不要安装单元测试和e2e测试。既然官⽅推荐我们使⽤这两个测试框架,那么我们就动⼿去学习实践⼀下他们吧。学习获取某信;wbxy68
简介
Karma
Karma是⼀个基于Node.js的JavaScript测试执⾏过程管理⼯具(Test Runner)。该⼯具在Vue中的主要作⽤是将项⽬运⾏在各种主流Web浏览器进⾏测试。
换句话说,它是⼀个测试⼯具,能让你的代码在浏览器环境下测试。需要它的原因在于,你的代码可能是设计在浏览器端执⾏的,在node 环境下测试可能有些bug暴露不出来;另外,浏览器有兼容问题,karma提供了⼿段让你的代码⾃动在多个浏览器(chrome,firefox,ie 等)环境下运⾏。如果你的代码只会运⾏在node端,那么你不需要⽤karma。
Mocha
Mocha是⼀个测试框架,在vue-cli中配合chai断⾔库实现单元测试。
Mocha的常⽤命令和⽤法不算太多,看阮⼀峰⽼师的测试框架 Mocha 实例教程就可以⼤致了解了。
⽽Chai断⾔库可以看Chai.js断⾔库API中⽂⽂档,很简单,多查多⽤就能很快掌握。
我对测试框架的理解
npm run unit 执⾏过程
执⾏ npm run unit 命令
开启Karma运⾏环境
使⽤Mocha去逐个测试⽤Chai断⾔写的测试⽤例
在终端显⽰测试结果
如果测试成功,karma-coverage 会在 ./test/unit/coverage ⽂件夹中⽣成测试覆盖率结果的⽹页。
Karma
对于Karma,我只是了解了⼀下它的配置选项。
下⾯是Vue的karma配置,简单注释了下:
var webpackConfig = require('../../st.conf')
Mocha和chai
我们看下官⽅的例⼦(都⽤注释来解释代码意思了):
import Vue from 'vue' // 导⼊Vue⽤于⽣成Vue实例
import Hello from '@/components/Hello' // 导⼊组件
// 测试脚本⾥⾯应该包括⼀个或多个describe块,称为测试套件(test suite)
describe('Hello.vue', () => {
// 每个describe块应该包括⼀个或多个it块,称为测试⽤例(test case)
it('should render correct contents', () => {
const Constructor = d(Hello) // 获得Hello组件实例
const vm = new Constructor().$mount() // 将组件挂在到DOM上
//断⾔:DOM中class为hello的元素中的h1元素的⽂本内容为Welcome to Your Vue.js App
expect(vm.$el.querySelector('.hello h1').textContent)
.to.equal('Welcome to Your Vue.js App')
})
})
需要知道的知识点:
测试脚本都要放在 test/unit/specs/ ⽬录下。
脚本命名⽅式为  [组件名].spec.js。
所谓断⾔,就是对组件做⼀些操作,并预⾔产⽣的结果。如果测试结果与断⾔相同则测试通过。
单元测试默认测试 src ⽬录下除了 main.js 之外的所有⽂件,可在 test/unit/index.js ⽂件中修改。
Chai断⾔库中,to be been is that which and has have with at of same 这些语⾔链是没有意义的,只是便于理解⽽已。
测试脚本由多个  descibe 组成,每个 describe 由多个 it 组成。
了解异步测试
it('异步请求应该返回⼀个对象', done => {
request
.get('api.github')
.end(function(err, res){
expect(res).to.be.an('object');
done();
});
});
了解⼀下 describe 的钩⼦(⽣命周期)
describe('hooks', function() {
before(function() {
// 在本区块的所有测试⽤例之前执⾏
});
after(function() {
// 在本区块的所有测试⽤例之后执⾏
});
beforeEach(function() {
// 在本区块的每个测试⽤例之前执⾏
});
afterEach(function() {
// 在本区块的每个测试⽤例之后执⾏
});
// test cases
});
实践
上⾯简单介绍了单元测试的⽤法,下⾯来动⼿在Vue中进⾏单元测试!
util.js
从Vue官⽅的demo可以看出,对于Vue的单元测试我们需要将组件实例化为⼀个Vue实例,有时还需要挂载到DOM上。
const Constructor = d(Hello) // 获得Hello组件实例
const vm = new Constructor().$mount() // 将组件挂载到DOM上
以上写法只是简单的获取组件,有时候我们需要传递props属性、⾃定义⽅法等,还有可能我们需要⽤到第三⽅UI框架。所以以上写法⾮常⿇烦。
这⾥推荐Element的单元测试⼯具脚本Util.js,它封装了Vue单元测试中常⽤的⽅法。下⾯demo也是根据该 Util.js来写的。
这⾥简单注释了下各⽅法的⽤途。
/**
* 回收 vm,⼀般在每个测试脚本测试完成后执⾏回收vm。
* @param  {Object} vm
*/
exports.destroyVM = function (vm) {}
/**
* 创建⼀个 Vue 的实例对象
* @param  {Object|String}  Compo    - 组件配置,可直接传 template
* @param  {Boolean=false}  mounted  - 是否添加到 DOM 上
* @return {Object} vm
*/
/**
* 创建⼀个测试组件实例
* @param  {Object}  Compo          - 组件对象
* @param  {Object}  propsData      - props 数据
* @param  {Boolean=false} mounted  - 是否添加到 DOM 上
* @return {Object} vm
*/
/**
* 触发⼀个事件
* 注: ⼀般在触发事件后使⽤ vm.$nextTick ⽅法确定事件触发完成。
* mouseenter, mouseleave, mouseover, keyup, change, click 等
* @param  {Element} elm      - 元素
* @param  {String} name      - 事件名称
* @param  {*} opts          - 配置项
*/
/
**
* 触发 “mouseup” 和 “mousedown” 事件,既触发点击事件。
* @param {Element} elm    - 元素
nodeselector
* @param {*} opts          - 配置选项
*/
⽰例⼀
⽰例⼀中我们测试了 Hello 组件的各种元素的数据,学习  util.js 的 destroyVM 和 createTest ⽅法的⽤法以及如何获取⽬标元素进⾏测试。获取DOM元素的⽅式可查看DOM 对象教程。
Hello.vue
<template>
<div class="hello">
<h1 class="hello-title">{{ msg }}</h1>
<h2 class="hello-content">{{ content }}</h2>
</div>
</template>
export default {
name: 'hello',
props: {
content: String
},
data () {
return {
msg: 'Welcome!'
}
}
}
</script>
Hello.spec.js
import { destroyVM, createTest } from '../util'
import Hello from '@/components/Hello'
describe('Hello.vue', () => {
let vm
afterEach(() => {
destroyVM(vm)
})
it('测试获取元素内容', () => {
vm = createTest(Hello, { content: 'Hello World' }, true)
expect(vm.$el.querySelector('.hello h1').textContent).to.equal('Welcome!')
expect(vm.$el.querySelector('.hello h2').textContent).to.have.be.equal('Hello World')
})
it('测试获取Vue对象中数据', () => {
vm = createTest(Hello, { content: 'Hello World' }, true)
expect(vm.msg).to.equal('Welcome!')
// Chai的语⾔链是⽆意义的,可以随便写。如下:
t).be.that.equal('Hello World')
})
it('测试获取DOM中是否存在某个class', () => {
vm = createTest(Hello, { content: 'Hello World' }, true)
expect(vm.$ains('hello')).ue
const title = vm.$el.querySelector('.hello h1')
expect(ains('hello-title')).ue
const content = vm.$el.querySelector('.hello-content')
expect(ains('hello-content')).ue
})
})
输出结果
Hello.vue
√ 测试获取元素内容
√ 测试获取Vue对象中数据
√ 测试获取DOM中是否存在某个class
⽰例⼆
⽰例⼆中我们使⽤ createTest 创建测试组件测试点击事件,⽤ createVue 创建Vue⽰例对象测试组件 Click 的使⽤。这⾥主要可以看下到 createVue ⽅法的使⽤。
Click.vue
<div>
<span class="init-num">初始值为{{ InitNum }}</span><br>
<span class="click-num">点击了{{ ClickNum }}次</span><br>
<span class="result-num">最终结果为{{ ResultNum }}</span><br>    <button @click="add">累加{{ AddNum }}</button>
</div>
</template>
<script>
export default {
name: 'Click',
props: {
AddNum: {
type: Number,
default: 1
},
InitNum: {
type: Number,
default: 1
}
},
data () {
return {
ClickNum: 0,
ResultNum: 0
}
},
mounted () {
this.ResultNum = this.InitNum
},
methods: {
add () {
this.ResultNum += this.AddNum
this.ClickNum++
this.$emit('result', {
ClickNum: this.ClickNum,
ResultNum: this.ResultNum
})
}
}
}
</script>
Click.spec.js
import { destroyVM, createTest, createVue } from '../util'
import Click from '@/components/Click'
describe('click.vue', () => {
let vm
afterEach(() => {
destroyVM(vm)
})