关键词:
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(‘../../build/webpack.test.conf‘)
module.exports = function (config) {
config.set({
// 浏览器
browsers: [‘PhantomJS‘],
// 测试框架
frameworks: [‘mocha‘, ‘sinon-chai‘, ‘phantomjs-shim‘],
// 测试报告
reporters: [‘spec‘, ‘coverage‘],
// 测试入口文件
files: [‘./index.js‘],
// 预处理器 karma-webpack
preprocessors: {
‘./index.js‘: [‘webpack‘, ‘sourcemap‘]
},
// Webpack配置
webpack: webpackConfig,
// Webpack中间件
webpackMiddleware: {
noInfo: true
},
// 测试覆盖率报告
// https://github.com/karma-runner/karma-coverage/blob/master/docs/configuration.md
coverageReporter: {
dir: ‘./coverage‘,
reporters: [
{ type: ‘lcov‘, subdir: ‘.‘ },
{ type: ‘text-summary‘ }
]
}
})
}
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 = Vue.extend(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(‘https://api.github.com‘) .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 = Vue.extend(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
*/
exports.createVue = function (Compo, mounted = false) {}
/**
* 创建一个测试组件实例
* @param {Object} Compo - 组件对象
* @param {Object} propsData - props 数据
* @param {Boolean=false} mounted - 是否添加到 DOM 上
* @return {Object} vm
*/
exports.createTest = function (Compo, propsData = {}, mounted = false) {}
/**
* 触发一个事件
* 注: 一般在触发事件后使用 vm.$nextTick 方法确定事件触发完成。
* mouseenter, mouseleave, mouseover, keyup, change, click 等
* @param {Element} elm - 元素
* @param {String} name - 事件名称
* @param {*} opts - 配置项
*/
exports.triggerEvent = function (elm, name, ...opts) {}
/**
* 触发 “mouseup” 和 “mousedown” 事件,既触发点击事件。
* @param {Element} elm - 元素
* @param {*} opts - 配置选项
*/
exports.triggerClick = function (elm, ...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>
<script>
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的语言链是无意义的,可以随便写。如下:
expect(vm.content).which.have.to.be.that.equal(‘Hello World‘)
})
it(‘测试获取DOM中是否存在某个class‘, () => {
vm = createTest(Hello, { content: ‘Hello World‘ }, true)
expect(vm.$el.classList.contains(‘hello‘)).to.be.true
const title = vm.$el.querySelector(‘.hello h1‘)
expect(title.classList.contains(‘hello-title‘)).to.be.true
const content = vm.$el.querySelector(‘.hello-content‘)
expect(content.classList.contains(‘hello-content‘)).to.be.true
})
})
输出结果
Hello.vue
√ 测试获取元素内容
√ 测试获取Vue对象中数据
√ 测试获取DOM中是否存在某个class
示例二
示例二中我们使用 createTest
创建测试组件测试点击事件,用 createVue
创建Vue示例对象测试组件 Click
的使用。这里主要可以看下到 createVue
方法的使用。
Click.vue
<template>
<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)
})
it(‘测试按钮点击事件‘, () => {
vm = createTest(Click, {
AddNum: 10,
InitNum: 11
}, true)
let buttonElm = vm.$el.querySelector(‘button‘)
buttonElm.click()
buttonElm.click()
buttonElm.click()
// setTimeout 的原因
// 在数据改变之后,界面的变化会有一定延时。不用timeout有时候会发现界面没有变化
setTimeout(done => {
expect(vm.ResultNum).to.equal(41)
expect(vm.$el.querySelector(‘.init-num‘).textContent).to.equal(‘初始值为11‘)
expect(vm.$el.querySelector(‘.click-num‘).textContent).to.equal(‘点击了3次‘)
expect(vm.$el.querySelector(‘.result-num‘).textContent).to.equal(‘最终结果为41‘)
done()
}, 100)
})
it(‘测试创建Vue对象‘, () => {
let result
vm = createVue({
template: `
<click @click="handleClick"></click>
`,
props: {
AddNum: 10,
InitNum: 11
},
methods: {
handleClick (obj) {
result = obj
}
},
components: {
Click
}
}, true)
vm.$el.click()
vm.$nextTick(done => {
expect(result).to.be.exist
expect(result.ClickNum).to.equal(1)
expect(result.ResultNum).to.be.equal(21)
done()
})
})
输出结果
click.vue
√ 测试按钮点击事件
√ 测试创建Vue对象
其他
所有示例代码都放Github仓库中便于查看。如果想查看更多好的测试用例,建议配合 Util.js
看一下 Element 的单元测试脚本的写法,里面有很多测试脚本可以供我们学习。作为被广大Vue用户使用的UI组件库,测试脚本肯定也写很很不错的~甚至可以将这些脚本照抄一遍,相信这会对学习Vue组件的单元测试有很大帮助。
下面是本人看Element单元测试的笔记,供参考。
- Util.js 方法包含了大多数Vue组件化的测试需求。
vm.$el
vm.$nextTick
和vm.$ref
都是在测试过程中比较常用的一些Vue语法糖。- 需要注意: vm.$nextTick 方法是异步的,所以需要在里面使用done方法。
- 异步断言,方法参数需要是
_
或者done
- 大多数时候查询元素通过
querySelector
方法查询class获得- vm.$el.querySelector(‘.el-breadcrumb‘).innerText
- 大多数情况下查询是否存在某个Class通过
classList.contains
方法获得,查找的结果为 true 或 false- vm.$el .classList.contains(‘el-button--primary‘)
- 异步测试必须以
done()
方法结尾。setTimeout
和vm.$nextTick
是常用的异步测试。 - 实现按钮点击:通过获取按钮元素
btn
,执行btn.click()
方法实现。 - 由于 Vue 进行 异步更新DOM 的情况,一些依赖DOM更新结果的断言必须在
Vue.nextTick
回调中进行。triggerEvent(vm.$refs.cascader.$el, ‘mouseenter‘); vm.$nextTick(_ => { vm.$refs.cascader.$el.querySelector(‘.el-cascader__clearIcon‘).click(); vm.$nextTick(_ => { expect(vm.selectedOptions.length).to.be.equal(0); done(); }); });
使用 Jest、Vue、Vuetify 和 Pug 运行单元测试
】使用Jest、Vue、Vuetify和Pug运行单元测试【英文标题】:RununittestwithJest,Vue,Vuetify,andPug【发布时间】:2020-07-3114:44:38【问题描述】:我目前正在开发一个项目,该项目使用Vue、基于类的组件、typescript、pug、vuetify和Jest进行单元测... 查看详情
使用 Jest 在 Vue 中为组件中的方法编写单元测试
】使用Jest在Vue中为组件中的方法编写单元测试【英文标题】:WriteunittestforamethodinacomponentinVuewithJest【发布时间】:2021-09-0517:57:36【问题描述】:我开始使用JestVue进行单元测试。我想测试一个Vue组件中的现有方法,我写了一个测... 查看详情
如何对使用 Axios(或其他异步更新)的 Vue 组件进行单元测试?
】如何对使用Axios(或其他异步更新)的Vue组件进行单元测试?【英文标题】:HowtounittestVuecomponentthatusesAxios(orotherasyncupdate)?【发布时间】:2019-05-1609:25:02【问题描述】:我有一个Vue组件/视图,它使用Axios执行API请求并使用响应... 查看详情
在 Vue 中使用外部模板文件进行单元测试
】在Vue中使用外部模板文件进行单元测试【英文标题】:UnitTestwithexternaltemplatefileinVue【发布时间】:2017-09-2002:05:27【问题描述】:我正在使用带有webpack模板的vue-cli,当我将模板文件拆分为不同的文件并运行npmrununit或yarnrununit时... 查看详情
如何使用 jest 在单元测试中测试引导 vue 组件的存在?
】如何使用jest在单元测试中测试引导vue组件的存在?【英文标题】:Howtotestfortheexistanceofabootstrapvuecomponentinunittestswithjest?【发布时间】:2019-11-2117:30:00【问题描述】:所以我有一些包含b-form-input组件的代码,我正在测试该组件是... 查看详情
Vue 和 Jest 单元测试组件
...:2019-01-0209:17:46【问题描述】:我是Vuejs的新手,我开始使用Jest进行单元测试。我不知道从哪里以及如何开始。我有这段Vue代码,我想用Jest进行测试。任何提示或想法我都会非常感激。我读到我应该使用Vuetest-utils中的shallowMount... 查看详情
Vue 单元测试:如何使用 props、vuex store、watchers、getter 等测试复杂组件
】Vue单元测试:如何使用props、vuexstore、watchers、getter等测试复杂组件【英文标题】:VueUnitTesting:Howtotestcomplexcomponentswithprops,vuexstore,watchers,gettersetc【发布时间】:2020-03-1407:20:23【问题描述】:我有一个关于vue应用程序中的单元测... 查看详情
单元测试 Vue JS 和 Vue 资源时状态不变
...:2016-12-2107:03:18【问题描述】:我正在尝试测试我创建的使用vue-resource进行API调用的服务。该服务应该进行调用并使用新数据更新组件,但是在我的测试中它没有注册更新的值。我使用与vue-cliwebpack示例相同的设置,并且我的身... 查看详情
使用 b 按钮“to”对 vue 路由进行单元测试
】使用b按钮“to”对vue路由进行单元测试【英文标题】:Unittestingvueroutingwithb-button"to"【发布时间】:2020-03-2203:04:09【问题描述】:我有一个包含来自VueBootstrap的b按钮组件的组件。在我的单元测试中,我想检查当我单击组... 查看详情
Vue,vuex:如何使用命名空间存储和模拟对组件进行单元测试?
】Vue,vuex:如何使用命名空间存储和模拟对组件进行单元测试?【英文标题】:Vue,vuex:howtounittestacomponentwithnamespacedstoreandmocking?【发布时间】:2020-08-0909:03:44【问题描述】:我正在使用vue、vuex和vuetify构建登录组件。我决定在商... 查看详情
事件点击单元测试VUE
...2:57:33【问题描述】:我的click-event测试无法运行。我正在使用Vuetify组件:v-btn,但我的click-event似乎没有调度。我尝试使用普通按钮标签,但结果相同。我是测试新手,这实际上是我的第一次运行,所以欢迎提示和指点。这是我... 查看详情
在单元测试中使用模拟获取响应时,Vue 组件无法呈现
】在单元测试中使用模拟获取响应时,Vue组件无法呈现【英文标题】:Vuecomponentfailstorenderwhenusingmockedfetchresponseinunittest【发布时间】:2021-07-0717:22:33【问题描述】:我想根据API提供的数据测试BootstrapVue表是否正确呈现。作为其中... 查看详情
运行测试单元时出现 VUE 错误
...7-07-2122:33:40【问题描述】:我刚刚添加了测试单元,当我使用npmrununit运行它时,我得到了错误并且测试将失败。但是,当我运行npmrundev时,一切看起来都很好,我不知道发生了什么黑客攻击。我想当我使用npmrununit运行时,sass-lo... 查看详情
Vue3 的 Quasar 单元测试
...orvue3【发布时间】:2021-10-2201:34:02【问题描述】:我正在使用quasar开发一个vue应用程序。我正在使用vue3.0.7。我已经安装了jest并创建了jest.config文件。jest配置文件包含以下内容:clearMocks:true,moduleFileExtensions:["js","jsx","ts","vue"], 查看详情
使用Vue组件的mocha进行单元测试时基类中的方法不存在
】使用Vue组件的mocha进行单元测试时基类中的方法不存在【英文标题】:MethodinbaseclassdoesnotexistduringunittestingwithmochaofVuecomponent【发布时间】:2019-08-2102:18:50【问题描述】:当我在Vue中有一个从基类扩展的组件时,它可以在浏览器... 查看详情
使用 Vue、Axios 和 Mocha 对 HTTP 请求进行单元测试
】使用Vue、Axios和Mocha对HTTP请求进行单元测试【英文标题】:UnittestingHTTPrequestwithVue,Axios,andMocha【发布时间】:2017-06-0523:48:03【问题描述】:我真的很难尝试使用Mocha/Chai-Sinon在VueJS中测试请求,使用Axios作为请求库,并尝试了Moxios... 查看详情
在vue-cli生成的项目中使用karma+chrome进行单元测试
...单元测试,那么会采用karma+mocha作为单元测试框架,默认使用的浏览器是PhantomJs。Karma是一个基于Node.js的JavaScript测试执行过程管理工具(TestRunner)。可启动所有主流Web浏览器作为测试容器,运行时会启动一个web服务器,生成包... 查看详情
如何在单元测试期间使用 vue-test-utils 和 jest 模拟 mixin?
】如何在单元测试期间使用vue-test-utils和jest模拟mixin?【英文标题】:Howtomockmixinduringunittestusingvue-test-utilsandjest?【发布时间】:2019-08-0719:55:35【问题描述】:我想在Test.vue中测试testMethod,但是testMethod使用了从App.js导入的mixin。Tes... 查看详情