文章目录
1. Jest 单元测试
-
安装:
npm i jest @types/jest
-
package.json 命令行:
"test:unit": "jest --clearCache && vue-cli-service test:unit"
单元测试文件写在 test/unit
目录下
- 常见命令:
{
"nocache": "jest --no-cache", //清除缓存
"watch": "jest --watchAll", //实时监听
"coverage": "jest --coverage", //生成覆盖测试文档
"verbose": "npx jest --verbose" //显示测试描述
}
-
默认会测试spec和test结尾的js文件,单元测试的文件名必须是xxxxxxxxx.spec.js或者xxxxxxxxx.test.js
-
测试函数
test("测试用列描述信息",()=>{})
// or
it("测试用例描述信息",()=>{})
- 断言函数
exspect(运行结果).toBe(期望的结果);
//常见断言方法
expect({a:1}).toBe({a:1})//判断两个对象是否相等
expect(1).not.toBe(2)//判断不等
expect({ a: 1, foo: { b: 2 } }).toEqual({ a: 1, foo: { b: 2 } })
expect(n).toBeNull(); //判断是否为null
expect(n).toBeUndefined(); //判断是否为undefined
expect(n).toBeDefined(); //判断结果与toBeUndefined相反
expect(n).toBeTruthy(); //判断结果为true
expect(n).toBeFalsy(); //判断结果为false
expect(value).toBeGreaterThan(3); //大于3
expect(value).toBeGreaterThanOrEqual(3.5); //大于等于3.5
expect(value).toBeLessThan(5); //小于5
expect(value).toBeLessThanOrEqual(4.5); //小于等于4.5
expect(value).toBeCloseTo(0.3); // 浮点数判断相等
expect('Christoph').toMatch(/stop/); //正则表达式判断
expect(['one','two']).toContain('one'); //不解释
- 例子
import { param2Obj } from '@/utils/index.js'
describe('Utils:param2Obj', () => {
const url = 'https://github.com/PanJiaChen/vue-element-admin?name=bill&age=29&sex=1&field=dGVzdA==&key=%E6%B5%8B%E8%AF%95'
it('param2Obj test', () => {
expect(param2Obj(url)).toEqual({
name: 'bill',
age: '29',
sex: '1',
field: window.btoa('test'),
key: '测试'
})
})
})
it
语法表示一个用例,expect
表示预期结果,toBe
表示三个等号的比较,如果条件成立单元测试即可通过。
2. Vue Test Utils
vue-test-utils 单元测试官网
安装: vue add @vue/unit-jest
- 例子
import { shallowMount } from '@vue/test-utils'
import Hamburger from '@/components/Hamburger/index.vue'
describe('Hamburger.vue', () => {
it('toggle click', () => {
const wrapper = shallowMount(Hamburger)
const mockFn = jest.fn()
wrapper.vm.$on('toggleClick', mockFn)
wrapper.find('.hamburger').trigger('click')
expect(mockFn).toBeCalled()
})
it('prop isActive', () => {
const wrapper = shallowMount(Hamburger)
wrapper.setProps({ isActive: true })
expect(wrapper.contains('.is-active')).toBe(true)
wrapper.setProps({ isActive: false })
expect(wrapper.contains('.is-active')).toBe(false)
})
})
3. karma 单元测试
# 1, 初始化时,需要选择打开test功能,然后选择karma测试
vue init webpack testtodo
# 2, 运行测试,test目录会出现coverage--icov-report--index.html
# 浏览器打开这个index.html,可以查看所有的测试地方
npm run unit
# 3, 安装vue.js 官方的单元测试实用工具库
npm install --save-dev @vue/test-utils@1.0.0-beta.12
mocha 是个测试框架,本身不带断言层,所以需要引进Chai 断言库实现单元测试
笔记总结
-
Util.js 方法包含了大多数Vue组件化的测试需求。
-
vm. e l v m . el vm. elvm.nextTick 和 vm. r e f 都 是 在 测 试 过 程 中 比 较 常 用 的 一 些 V u e 语 法 糖 。 需 要 注 意 : v m . ref 都是在测试过程中比较常用的一些Vue语法糖。 需要注意: 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 是常用的异步测试。
由于 Vue 进行异步更新 DOM 的情况,一些依赖 DOM 更新结果的断言必须在 vm.$nextTick() resolve 之后进行:
// 引用vue
import Vue from 'vue';
// 引用要测试的组件
import app from '../../src/app.vue';
// 描述要测试的内容
describe('test app.vue', () => {
// 异步数据更新
it('数据更新后,视图应该改变', done => {
// 这里将app生成vue实例,并使用 $mount() 模拟挂载状态
let vm = new Vue(app).$mount();
// 挂载后改变title
vm.title = 'APP';
Vue.nextTick(() => {
let title = vm.$el.getElementsByTagName('h1')[0]
expect(title.textContent).toEqual('APP')
done();
})
});
});
describe 的钩子(生命周期)
describe('hooks', function() {
before(function() {
// 在本区块的所有测试用例之前执行
});
after(function() {
// 在本区块的所有测试用例之后执行
});
beforeEach(function() {
// 在本区块的每个测试用例之前执行
});
afterEach(function() {
// 在本区块的每个测试用例之后执行
});
// test cases
});
官方Demo的HelloWorld.spec.js代码
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')
})
})
4. 单元测试实例Demo代码
<template>
<div>
<section class="todoapp">
<header class="header">
<h1>todos</h1>
<input v-model="newtodo" @keyup.enter="addtodo" class="newtodo" autofocus autocomplete="off"
placeholder="what needs to be done?" >
</header>
<section class="main" >
<ul class="todo-list">
<li v-for="todo in todos" :key="todo.id" class="todo" >
<div class="view">
<label>{{todo.text}}</label>
<button @click="deltodo(todo)" class="destroy">删除</button>
</div>
<input v-model="todo.text" class="edit" type="text"/>
</li>
</ul>
</section>
</section>
</div>
</template>
<script>
export default {
name: 'todoMVC',
data () {
return {
todos:[
{ id:Math.random(), text:"CSS" },
{ id:Math.random(), text:"html" }
],
newtodo:''
}
},
methods:{
addtodo:function(){
this.todos.push(
{
id: Math.random(),
text:this.newtodo
}
)
this.newtodo=''
},
deltodo:function(todo){
let index = this.todos.indexOf(todo);
this.todos.splice(index,1)
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
html,body{
margin: 0;
padding: 0;
}
button {
margin: 10px 30px;
padding: 5px;
border: 1px;
background: rgb(126, 167, 126);
font-size: 100%;
}
body{
line-height: 1.4em;
}
</style>
todoMVC.spec.js 文件—测试用例
import {mount} from '@vue/test-utils'
import todoMVC from '@/components/todoMVC'
// 创建测试套件
describe('HelloWorld.vue', () => {
// 创建-- 查看 --测试用例
it('测试查看功能', () => {
// 通过mount 将组件渲染出来
const wrapper = mount(todoMVC);
// 寻找制定的dom元素
console.log(wrapper.find('.todo-list'))
// 通过vm查看data中的某个数据
console.log(wrapper.vm.todos)
// 断言
expect(wrapper.vm.todos.length).to.be.equal(2)
})
// 创建-- 增加 --测试用例
it('测试增加功能', () => {
// 通过mount 将组件渲染出来
const wrapper = mount(todoMVC);
// 1, 对newtodo进行赋值
wrapper.setData({newtodo: 'test-word'})
// 2,对new-todo触发回车事件
wrapper.find('.newtodo').trigger('keyup.enter')
// 3,断言,检查todos中是否有数据增加
expect(wrapper.vm.todos.length).to.be.equal(3)
expect(wrapper.vm.todos[2].text).to.be.equal("test-word")
console.log(wrapper.vm.todos)
})
// 创建-- 删除 --测试用例
it('测试删除功能', () => {
// 通过mount 将组件渲染出来
const wrapper = mount(todoMVC);
wrapper.find('.destroy').trigger('click')
expect(wrapper.vm.todos.length).to.be.equal(1)
})
})