vue单元测试vue test utils使用初探
简介
最近在做一个项目的重构,技术选型为vue-cli 3.0 + typescript + vue-router + sass.因为我负责的模块比较少比较简单,所以老大让我先把负责部分的测试代码写好。至此我才第一次接触到测试代码,我们项目使用的测试工具是jest,与vue官方出的单元测试工具库vue-test-utils配合使用。第一次接触测试代码,开始的时候还是一脸懵逼,有种学习一门新语言的赶脚。经过几天的摸索之后学会了简单的编写测试代码,并对几种情况进行特殊处理。本文是一篇vue单元测试的基础入门文章,只介绍测试代码,需要了解搭建测试框架的朋友可以自行参阅vue-test-utils官方文档等资料。
1.什么是测试代码
简言之,测试代码就是通过代码模拟一个vue组件的运行环境,使被测试的组件在这个环境下运行看是否能够得到期望的运行结果。如果运行结果与期望的结果相同,则说明该测试用例通过。下面我们来看一个最简单的实例:
- 一个简单的vue组件的测试
// message.vue
<template><div><p>{{message}}</p></div>
<template>
<script>export default{data(){return{message: 'a test component',}}}
</script>
复制代码
上面这个最简单的vue组件,就是将data中的message值渲染到p标签中去。对与这样的组件,测试代码如下
import { mount } from '@vue/test-utils';
import message from './message.vue';
describe('测试message.vue组件的测试套件,可含有多个测试用例', () =>{it('这是测试message组件p标签能否正常渲染文字的一个测试测试用例', () => {const wrapper = mount(message, {}) // 使用mount可以创建一个包涵被挂载和渲染的一个实例expect(wrapper.find('p').text()).toBe('a test component') // expect是jest中的断言,即判断该语句前后是否相等})
})
复制代码
上面这句expect().toBe()断言,用于判断我们用message.vue组件生成的实例中,p 标签中的文字是否等于组件 data 中的 message 的值'a test component',如果相等,则说明此断言为真。
- 一个稍复杂组件的测试
// count.vue
<template><div><p>{{count}}</p><button @click="add">增加</button></div>
</template>
<script>
export default {data() {return{count: 0}},methods: {add() {this.count++}},
}
</script>
复制代码
上面是一个带有简单交互的vue组件,count初始值为0,用户点击一次增加按钮,p标签中的值即加一。对于这样的组件我们的测试代码为
import { mount } from '@vue/test-utils';
import count from 'count.vue';
describe('count.vue组件', () => {it('测试count组件能否正常显示并增加', () => {const wrapper = mount(count, {}) // 使用 mount 创建一个vue组件实例 wrapperexpect(wrapper.find('p').text()).toBe(0); // 判断p标签中的值是否为初始化0wrapper.find('button').trigger('click'); // 使用trigger('click')模拟用户的点击操作expect(wrapper.find('p').text()).toBe(1); // 经过模拟点击操作后,count的值应该增加成为1})
})
复制代码
通过上面的例子我们看到,测试代码可以模拟出用户的操作,通过对操作之后的结果进行断言,能判断出该组件能否通过测试。而且一个测试用例中可以有多个断言,只有全部断言通过才说明该组件实例通过测试。只要有一个断言未通过,则说明该组件实例未通过测试。
2.测试带有回调的异步请求
在项目中我们很常见到vue组件内向接口请求数据的情况,那么我们如何测试这种异步请求呢。官方也给了我们实例代码:
// axios模拟
export default{get: () => Promise.resolve({ date: 'value' })
}
复制代码
// getValue.vue
<template><button @click="fetchResults" />
</template>
<script>import axios from 'axios'export default {data() {return {value: null}},methods: {async fetchResults() {const response = await axios.get('mock/service')this.value = response.data}}}
</script>
复制代码
// getValue.test.js
import { shallowMount } from '@vue/test-utils'
import Foo from './Foo'
jest.mock('axios') // jest 模拟axios库describe('getValue.vue组件', () => {it('点击button时,异步获取接口返回的value值', done => {const wrapper = shallowMount(Foo)wrapper.find('button').trigger('click')wrapper.vm.$nextTick(() => { // 使用$nextTick 在Promise执行后再进行断言expect(wrapper.vm.value).toBe('value') // 对异步获取的数据进行断言,判断获取的值与期望是否都相等done() // 使用done()结束回调})})
})
复制代码
上面的这个官方demo是通过调用组件内的接口,并对接口返回的数据进行断言。一开始我也照着官方给的代码使用,但是很快发现了一些随之出现的问题。
1. 调用组件本身的接口,意味着需要在组件内部传入接口请求时所需要的参数,这个数据我们可以自己传入创建的vue实例中,但是如果对于全部接口都自己传入数据会非常麻烦。而且还分成传入的参数正确或错误等不同情况。
2. 调用vue组件本身的http请求测试,必须得有后台接口配合,不能独立出来测试。而且测试会对后台产生真实的请求记录,因为我们开发过程中不知道会测试多少次,所以会给后台添加很多无用的请求记录。
3. 因为公司开发项目时,使用的是docker创建的虚拟容器作为运行环境,配置了网络地址转发,这使得我vue组件中的请求无法成功,也是这条因素使得我不能使用官方给的测试方法。
然后我就请教了我们的老大,在他的帮助下我使用另一种方法测试异步请求,做法是拦截组件中的异步请求,使用自己模拟的http请求。代码如下:
// 需要改造一下我们的 axios 请求
import axios from 'axios'
export getValue(...arg){return axios.get('mock/service',..arg).then(res=>{Promise.resolve({ date: 'value' })})
}
复制代码
// getValue.vue
<template><button @click="fetchResults" />
</template>
<script>import getValue from 'axios'export default {data() {return {value: null}},methods: {fetchResults() {getValue(...arg).then(res=>{this.value = res.date})}}}
</script>
复制代码
// getValue.test.js
import { shallowMount } from '@vue/test-utils'
import * as svc from 'axios'
import Foo from './Foo'describe('getValue.vue组件', () => {it('点击button时,异步获取接口返回的value值', done => {const getValue = jest.spyOn(svc, 'getValue') // 使用jest.spyOn()创建一个mock函数getValue.mockReturnValueOnce(Promise.resolve({data: 'value')) // 模拟我们自己mock函数的返回值const wrapper = shallowMount(Foo)wrapper.find('button').trigger('click') // 模拟用户点击事件wrapper.vm.$nextTick(() => { // 使用$nextTick 在Promise执行后再进行断言expect(getValue).toBeCalled(); // 断言是否请求了自己mock的getValue函数expect(wrapper.vm.value).toBe('value') // 对异步获取的数据进行断言,判断获取的值与期望是否都相等done() // 使用done()结束回调})})
})
复制代码
jest.spyOn()方法创建一个mock函数,这个mock的函数会在组件的接口请求的时候被执行,并返回我们给mock函数添加的返回值,通过判断这个mock函数是否被执行,以及组件获取的返回值与我们给mock函数添加的返回值是否相等就可以判断组件的异步请求是否能够正确执行。通过这种方式,我们来测试异步组件。
实际上我的同事,之前也写过一篇在react项目中使用jest测试的文章,其中也介绍了使用jest.spyOn()来测试异步请求的情况。感兴趣的话可以去这里结合了解一下。
3. 测试在有路由情况下的vue组件
vue 官方也给出了vue-test-util 配合 vue-router 使用的文档。我工作中出现的一个情况是要测试在某个路由地址下,<router-view>
加载的子组件的测试。但是到目前为止本人还没有按照官方的实例跑通过测试,很尴尬,也许是我打开的姿势不对,等之后正确实现之后会把方法再补上。下面我介绍一个对这种情况测试的非官方的写法。
import Vue from 'vue'
import VueRouter from 'vue-router'
import totest from 'src/components/totest'describe('totest.vue', () => {it('should totest renders stuff', (done) => {Vue.use(VueRouter)const router = new VueRouter({routes: [ // 定义路由,其中使用了被测试组件{path: '/totest/:id', name: 'totest', component: totest},{path: '/wherever', name: 'another_component', component: {render: h => '-'}},]})const vm = new Vue({ // 自己新建一个带 router 且有 router-view 的vue实例el: document.createElement('div'),router: router,render: h => h('router-view')})router.push({name: 'totest', params: {id: 123}}) // 使用测试组件的路由Vue.nextTick(() => {console.log('html:', vm.$el)expect(vm.$el.querySelector('h2').textContent).to.equal('Fred Bloggs');done()})})
})
复制代码
上面这个测试代码很巧妙的新建了一个使用router的vue实例,然后把被测试组件加到路由中去,当改变路由地址时,被测试组件就会被执行。此时可以对被测试组件进行断言。
4. 其他问题
在开发过程中还遇到了一些其他问题,如:
1. vue项目使用了element组件,测试代码报错,类似于 el-button 未注册
2. 项目使用了vue-i18n做国际化,测试代码报错,报错信息为 vm._$t is not a function...
3. 使用国际化vue-i18n的时候,vue组件代码里如果有 i18n.locale
的话测试代码会提示无法找到locale属性
..........
上面我列出来的这三个问题,并没有给出具体的解决办法。12解决比较简单,3目前还不知道如何处理...之后请教一下我们的大佬或者自己查阅下资料,等解决之后再来更新文章。因为每个人的项目不一样,可能我遇到的问题别人并不会遇到,所以还是对着报错自己查照调试吧。这也能更加完善你自己的项目代码。本人也是小白,第一次学习写测试代码,之后有了更深入的了解之后会更新这篇文章。
参考文章
vue-test-utils官方
一篇文章学会 Vue 项目单元测试
原文链接:tech.gtxlab.com/vue-test-ut…
作者简介: 宫晨光,人和未来大数据前端工程师。
转载于:https://juejin.im/post/5ca56c2551882543fa41d51f
vue单元测试vue test utils使用初探相关推荐
- 使用Tape和Vue Test Utils编写快速的Vue单元测试
by Edd Yerburgh 埃德·耶堡(Edd Yerburgh) 使用Tape和Vue Test Utils编写快速的Vue单元测试 (Write blazing fast Vue unit t ...
- 前端自动化测试——vue单元测试vue-test-utils
自动化测试分类 单元测试 单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证.简单来说,单元就是人为规定的最小的被测功能模块,可能是一个单一函数或方法.一个完整的组件或类 ...
- jset编写测试vue代码_使用 Jest 进行 Vue 单元测试
本文介绍: 1.vue-cli3下jest环境的搭建 2.vue组件基本的测试方法 环境配置 vue-cli3 的插件使安装流程变得格外简单,通过 vue ui 启动可视化管理系统,在插件栏,点击 ' ...
- vue 单元测试报错之 undefined is not a constructor (evaluating 'expect(vmComponent.count).toBe(1)')
下面是按照vue官方的例子,写的测试, // MyComponent.spec.js import Vue from 'vue' import MyComponent from '@/componen ...
- 【Vue】Vue项目开发目录结构和引用调用关系
main.js ->找到index.html中的挂载位置->找到app.vue中的挂载内容 原文:https://www.cnblogs.com/chenleideblog/p/10432 ...
- [vue] 使用vue开发过程你是怎么做接口管理的?
[vue] 使用vue开发过程你是怎么做接口管理的? 创建一个request.js用于封装axios,在 src/api/request,设置拦截器统一处理请求和相应.封装 axios:request ...
- 为什么我们放弃了 Vue?Vue 和 React 深度对比
我使用 Vue 和 React 已经很长一段时间了,两个框架上实践代码量都在 10 万行以上.不得不说两者都是很 nice 的,帮助开发者减少很多工作量,这类框架是现代化前端开发必备的.然而 Vue ...
- 登录页面html引入vue,用vue写简单的登录注册总结
步骤一 1.安装脚手架:npm install vue-cli -g 2.wepack生成html模版:vue init webpack ' 文件名' 3.安装axios.js-cookie.elem ...
- vue引入cdn Vue 优化Vue引入 cdn vue cdn Vue优化引入CDN vue 项目 CDN优化
vue引入cdn Vue 优化Vue引入 cdn vue cdn Vue优化引入CDN vue 项目 CDN优化 未引入 CDN前 main.js 更改CDN方式引入 在 vue.config 中引入 ...
- vue-plugin-hiprint vue hiprint vue使用hiprint打印控件VUE HiPrint HiPrint简单使用
vue-plugin-hiprint vue hiprint vue使用hiprint打印控件VUE HiPrint HiPrint简单使用 安装相关依赖 安装 vue-plugin-hiprint ...
最新文章
- python监控进程状态_python监控进程脚本
- rabbitmq容器在运行中会根据异常等级(Fatal)认为不可恢复
- 《Linux From Scratch》第二部分:准备构建 第五章:构建临时文件系统- 5.2 工具链技术备注...
- FastDfs上传图片时报错configparser.NoOptionError: No option ‘connect_timeout‘ in section: ‘__config__‘
- 低学历的非要考研,多半输得更惨
- 关于C/C++中的几个关键字(C基础)
- JavaScript之改变样式
- 二、SpringBoot配置文件讲解
- Bailian2795 金银岛【背包+贪心】
- 集合字典序(优先队列)
- 【IT职场】2013中国IT领袖峰会马云演讲实录
- 组件分享之后端组件——用Go编写的IMAP4rev1库go-imap
- 用python做网站的步骤_Python建网站的步骤
- 360公司 2020秋招 技术综合E卷 在线考试 编程题 第一题 表面积(web前端)
- 应用统计专业硕士的就业前景如何?
- 【信息安全案例】——系统软件安全(学习笔记)
- 【手机远程连接电脑or服务器】【向日葵远程连接版】
- Segmenting tree crowns from terrestrial and mobile LiDAR data by exploring ecological theories
- python networkx进行最短路径分析_【Python学习系列二十六】networkx库图最短路径求解...
- qc35 说明书_BOSE QC35
热门文章
- python爬虫js加密篇—搜狗微信公号文章的爬取
- USB3.0 Micro-B引脚定义和封装尺寸
- python中的猴子补丁Monkey Patch
- postgresql点云las_三维点云目标提取总结【转】
- 使用canvas保存网页为pdf文件支持跨域
- rtl8211 smi读取_RTL8211E应用(二)之信号输入、输出接口
- altium designer(AD13)隐藏敷铜的方法
- ABBYY FineReader15老牌ocr文字识别软件
- 大学生搜题软件哪个好用?2020搜题软件排行榜
- Ubuntu 18.10 下安装CUDA10/CUDA10.1