jest是Facebook的一套开源的JavaScript测试框架,它集成了快照测试、断言、mock以及覆盖率报告等功能,很全面而且基本不需要太多的配置便可使用Vue-Test-Utils是Vue的官方的单元测试框架,它提供了一系列非常方便的工具,使我们更加轻松的为Vue构建的应用来编写单元测试。
      这里讲的主要是Vue+Jest+Vue-Test-Utils的项目,假设现在你已经使用vue-cli3搭建了一个vue项目:
 
1.安装jest
npm install --save-dev jest @vue/test-utils

//package.json
"scripts": {
"test": "jest",
}
 
2.vue-jest
vue-jest是一个 预处理器,如果不安装vue-jest,jest无法处理.vue
npm install --save-dev vue-jest
 
3.配置jest
在src/test目录新建jest.conf.js配置文件,目录如下:
aaarticlea/png;base64,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" alt="">
 
我的配置内容如下:
const path = require('path');

module.exports = {
verbose: true,
testURL: 'http://localhost/',
rootDir: path.resolve(__dirname, '../../../'),
moduleFileExtensions: [
'js',
'json',
'vue',
],
testMatch: [ // 匹配测试用例的文件
'<rootDir>/src/test/unit/specs/*.spec.js',
],
transform: {
'^.+\\.js$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest',
},
testPathIgnorePatterns: [
'<rootDir>/test/e2e',
],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
}, };
 
4.配置之后就可以开始写测试用例了
在spec目录下新建一个ATest.spec.js文件(jest的测试脚本为.spec.js为后缀)
//ATest.vue组件
<template>
<div>
<Checkbox class="checkAlls" @on-change="checkboxChange" v-model="checkAll">全选</Checkbox>
</div>
</template>
<script>
export default {
name: 'ATest',
data() {
return {
checkAll: false,
};
},
methods: {
checkboxChange(value) {
this.$emit('on-change', value);
},
},
};
</script>
 
ATest.spec.js测试文件
import { mount, createLocalVue } from '@vue/test-utils';
import ATest from '@/components/ATest.vue';
import iviewUI from 'view-design'; const localVue = createLocalVue();
localVue.use(iviewUI); describe('ATest.vue',()=>{
const wrapper =mount(ATest, {
localVue
}); it("事件被正常触发",()=>{
const stub = jest.fn();
wrapper.setMethods({ checkboxChange: stub });
//触发自定义事件
wrapper.find(".checkAlls").vm.$emit("on-change");
wrapper.setData({checkAll: true});
expect(wrapper.vm.checkAll).toBe(true);
})
})
 
5.vue-test-utils常用的API
  • mount()
     创建一个包含被挂载和渲染的 Vue 组件的 wrapper,它仅仅挂载当前实例
  • shallowMount()
   和 mount 一样,创建一个包含被挂载和渲染的 Vue 组件的 Wrapper,只挂载一个组件而不渲染其子组件 (即保留它们的存根),这个方法可以保证你关心的组件在渲染时没有同时将其子组件渲染,避免了             子组件可能带来的副作用(比如Http请求等)
 
   mount和shallowMount区别的案例解释
//App.vue
<template>
<div id="app">
<Page :messages="messages"></Page>
</div>
</template>
 
//子组件
<template>
<div>
<p v-for="message in messages" :key="message">{{message}}</p>
</div>
</template>
 
//测试用例App.spec.js
import { mount } from 'vue-test-utils';
import App from '@/App';
describe('App.test.js', () => {
let wrapper;
let vm;
beforeEach(() => {
wrapper = mount(App);
vm = wrapper.vm;
wrapper.setProps({ messages: ['Cat'] })
});
// 为App的单元测试增加快照(snapshot):
it('has the expected html structure', () => {
expect(vm.$el).toMatchSnapshot()
})
});
 
执行单元测试后,测试通过,然后Jest会在test/__snapshots__/文件夹下创建一个快照文件App.spec.js.snap
exports[`App.test.js has the expected html structure 1`] = 
` <div id="app" > <div> <p> Cat </p> </div> </div> `;
 
//通过快照我们可以发现,子组件Test1被渲染到App中了。
 
将App.spec.js中的mount方法更改为shallow方法,再次查看快照
exports[`App.test.js has the expected html structure 1`] = 
` <div id="app" > <!----> </div> `;
 
//可以看出来,子组件没有被渲染
该案例的详细解释可以看这篇文章: https://blog.csdn.net/duola8789/article/details/80434962
  • createLocalVue
   返回一个 Vue 的类供你添加组件、混入和安装插件而不会污染全局的 Vue 类
import { createLocalVue, shallowMount } from '@vue/test-utils'import Foo from './Foo.vue'
const localVue = createLocalVue()const wrapper = shallowMount(Foo, {
localVue,
mocks: { foo: true }})expect(wrapper.vm.foo).toBe(true)
const freshWrapper = shallowMount(Foo)expect(freshWrapper.vm.foo).toBe(false)
  • 选择器 (详细看Vue-Test-Utils官网介绍)
  • $route 和 $router
import { mount} from '@vue/test-utils'
import Test from '@/components/common/Test.vue';
describe('Test.vue',()=>{
const wrapper = mount(Test, {
mocks: {
$route: { path: '/login' }
}
})
it("test", ()=>{
expect(wrapper.vm.$route.path).toMatch('/login')
})
})
  • 状态管理Vuex
import Vuex from 'vuex';
import {mount, createLocalVue} from '@vue/test-utils'; const localVue = createLocalVue();
localVue.use(Vuex);
describe('Test.vue',()=>{
let wrapper;
let getters;
let store;
let action;
let mutations;
let option;
beforeEach(()=>{
state = {
name: '张三'
}
getters = {
GET_NAME: ()=> '张三'
}
mutations = {
SET_NAME: jest.fn()
}
action = {
setName: jest.fn()
}
store = new Vuex.Store({
getters,
mutations,
action
})
option = {
store,
localVue
}
wrapper = mount(Test, option)
}) it("测试vuex", ()=>{
expect(getters.GET_Name()).toEqual('张三');
wrapper.vm.$store.state.name= "李四";
expect(wrapper.vm.name).toMatch('李四');
wrapper.find('.btn').trigger('click')
expect(actions.setName).toHaveBeenCalled()
wrapper.find({ref: 'testComp'}).vm.$emit('on-select');
expect(mutations.SET_NAME).toBeCalled()
}) })
  • wrapper
          一个 Wrapper 是一个包括了一个挂载组件或 vnode,以及测试该组件或 vnode 的方法
         属性      
         setMethods: 设置 Wrapper vm 的方法并强制更新。 通过setMethods方法用mock函数代替真实的方法,然后就可以断言点击按钮后对应的方法有没有被触发、触发几次、传入的参数等等
 
6.测试钩子
  • beforeEach(fn)  在每一个测试之前需要做的事情,比如测试之前将某个数据恢复到初始状态
  • afterEach(fn)       在每一个测试用例执行结束之后运行
  • beforeAll(fn)          在所有的测试之前需要做什么
  • afterAll(fn)             在测试用例执行结束之后运行
他们的调用顺序为: beforeAll =>  beforeEach =>  afterAll =>  afterEach
 
7.模拟接口请求
//Test.vue
mounted() {
this.getDataList();
}, methods: {
getDataList() {
this.$api.data.getData().then((res) => {
this.List= res.data;
});
} import {shallowMount, createLocalVue} from '@vue/test-utils';
const localVue = createLocalVue();
 
//axios请求
jest.mock('../data.js', ()=>({
getData: () => Promise.resolve({data:{name:'张三'}})
}))
describe('Test.vue',()=>{
const option;
let wrapper =shallowMount(Test, option)
it("异步接口被正常执行", async()=>{
const getDataList= jest.fn();
option.methods = {getDataList};
shallowMount(Test, option);
await expect(getDataList).toBeCalled();
}) it('测试异步接口的返回值', () => {
return localVue.nextTick().then(() => {
expect(wrapper.vm.List).toEqual( {name:'张三'});
})
}) })
 
7.常见的报错
[vue-test-utils]: find did not return .btn, cannot call trigger() on empty Wrapper
//出现该问题的时候,除了要确保你的组件确实存在该类名的情况,还要确保存在v-if的时候是否为true,如果为false,只需要在单测里将其设置为true,该问题便可解决
 "ReferenceError: sessionStorage is not defined"
//出现该问题只需要去模拟本地存储就可以了,npm提供了一个模拟本地存储数据的依赖包mock-local-storage,安装后在单测文件里导入即可
//import 'mock-local-storage';
//包地址:https://www.npmjs.com/package/mock-local-storage
TypeError: Cannot read property xxxx of undefined
//这个问题的一般解决方法是直接mock数据
wrapper = mount(Test, {

mocks:{

    $router:[],  //不然可能会报  Cannot read property 'push' of undefined,

    $cacheKeys: { TOKEN: 1 }, //  Cannot read property 'TOKEN' of undefined

}

})

 
注:要明白测试的目的,测试关心是我们的代码有没有达到我们预期的效果,它并不关心实现的过程,所以不需要太过于纠结变量的取值或者其他的问题
 
8、覆盖率报告
单元测试有四个指标:
  • %stmts是语句覆盖率(statement coverage):是否每个语句都执行了?

  • %Branch分支覆盖率(branch coverage):是否每个if代码块都执行了?

  • %Funcs函数覆盖率(function coverage):是否每个函数都调用了?

  • %Lines行覆盖率(line coverage):是否每一行都执行了?

   jest提供了生成测试覆盖率报告的命令
  • npx jest --init 生成配置文件jest.config.js
  • package.json添加上 --coverage 这个参数
//修改package.json
"scripts": {
"test": "jest --coverage"
}

npm run test之后会生成coverage文件

然后再网页打开index.html,就会看到下图

三种颜色分别代表不同比例的覆盖率(<50%红色,50%~80%灰色, ≥80%绿色)

点击文件名可以查看代码的执行情况,

旁边显示的1x代表执行的次数

                          jest官网:https://jestjs.io/docs/en/getting-started
            vue-jest-utils官网:https://vue-test-utils.vuejs.org/zh/guides/
单元测试的相关参考链接:https://alexjover.com/blog/

vue+jest+vue-test-utils 单元测试的更多相关文章

  1. 前端单元测试,以及给现有的vue项目添加jest + Vue Test Utils的配置

    文章原址:https://www.cnblogs.com/yalong/p/11714393.html 背景介绍: 以前写的公共组件,后来需要添加一些功能,添加了好几次,每次修改我都要测试好几遍保证以 ...

  2. 如何为我的VUE项目编写高效的单元测试--Jest

    Unit Testing(单元测试)--Jest 一个完整的测试程序通常由几种不同的测试组合而成,比如end to end(E2E)测试,有时还包括整体测试.简要测试和单元测试.这里要介绍的是Vue中 ...

  3. vue项目工具文件utils.js javascript常用工具类,javascript常用工具类,util.js

    vue项目工具文件utils.js :https://blog.csdn.net/Ajaxguan/article/details/79924249 javascript常用工具类,util.js : ...

  4. Vue 项目 Vue + restfulframework

    Vue 项目 Vue + restfulframework 实现登录认证 - django views class MyResponse(): def __init__(self): self.sta ...

  5. vue学习之用 Vue.js + Vue Router 创建单页应用的几个步骤

    通过vue学习一:新建或打开vue项目,创建好项目后,接下来的操作为: src目录重新规划——>新建几个页面——>配置这几个页面的路由——>给根实例注入路由配置 src目录重整 在项 ...

  6. vue --- 解读vue的中webpack.base.config.js

    const path = require('path') const utils = require('./utils')// 引入utils工具模块,具体查看我的博客关于utils的解释,utils ...

  7. vue — 创建vue项目

    创建vue项目 在程序开发中,有三种方式创建vue项目,本地引入vuejs.使用cdn引入vuejs.使用vue-cli创建vue项目.其中vue-cli可以结合webpack打包工具使用,大大方便了 ...

  8. vue入门 vue与react和Angular的关系和区别

    一.为什么学习vue.js vue.js兼具angular.js和react的优点,并且剔除了他们的缺点 官网:http://cn.vuejs.org/ 手册:http://cn.vuejs.org/ ...

  9. Vue (三) --- Vue 组件开发

    ------------------------------------------------------------------好心情,会让你峰回路转. 5. 组件化开发 5.1 组件[compo ...

随机推荐

  1. java 合并流(SequenceInputStream)

    需要两个源文件,还有输出的目标文件 SequenceInputStream: 将两个文件的内容合并成一个文件 该类提供的方法: SequenceInputStream(InputStream s1, ...

  2. 【js】 vue 2.5.1 源码学习(十二)模板编译

    大体思路(十) 本节内容: 1. baseoptions 参数分析 2. options 参数分析 3. parse 编译器 4. parseHTNL 函数解析 // parse 解析 parser- ...

  3. WPF 使用 Composition API 做高性能渲染

    在 WPF 中很多小伙伴都会遇到渲染性能的问题,虽然 WPF 的渲染可以甩浏览器渲染几条街,但是还是支持不了游戏级的渲染.在 WPF 使用的 DX 只是优化等级为 9 和 DX 9 差不多的性能,微软 ...

  4. 开源项目使用 appveyor 自动构建

    我写了几个开源项目,我想要有小伙伴提交的时候自动运行单元测试,自动运行编译,这样可以保证小伙伴提交清真的代码 本文将会告诉大家如何接入 appveyor 自动构建方案,在 Github 上给自己的开源 ...

  5. post提交方式为什么要序列化,而Get提交方式就不用?序列化做了什么?

    这是因为后台能够直接处理的数据格式,是一种经过序列化的键值对数据,比如前端要向后台提交三个参数,分别是a=1,b=2,c=3,那么后台接收到的数据就应该是a=1&b=2&c=3(可以看 ...

  6. 在js中arguments对象的理解

    一.在函数调用的时候,浏览器每次都会传递进两个隐式参数 函数的上下文对象this 封装实参的对象arguments 二.arguments 对象 arguments 对象实际上是所在函数的一个内置类数 ...

  7. 51nod 挑剔的美食家

    挑剔的美食家    基准时间限制:1 秒 空间限制:131072 KB 分值: 5 与很多奶牛一样,Farmer John那群养尊处优的奶牛们对食物越来越挑剔,随便拿堆草就能打发她们午饭的日子自然是一 ...

  8. vue-learning:34 - component - 内置组件 - 缓存组件keep-alive

    vue内置缓存组件keep-alive <keep-alive>标签内包裹的组件切换时会缓存组件实例,而不是销毁它们.避免多次加载相应的组件,减少性能消耗.并且当组件在 <keep- ...

  9. MYSQL调优实战

    一:基础数据准备 DROP TABLE IF EXISTS `tbl_user`; CREATE TABLE `tbl_user` ( `id` ) NOT NULL AUTO_INCREMENT, ...

  10. 浅析Java hashCode()方法

      散列码(hash code)是由对象导出的一个整数值. 散列码没有规律,两个不同的对象x和y,x.hashCode()与y.hashCode()基本上不会相同. public static voi ...