当我初次听到单元测试时,心里的第一感觉就两个字nb,然后就是疑惑,这是啥,干啥用,对代码又有什么帮助?接下来我会细细说一说我在学习以及应用单元测试的一些心得。(安装教程不再叙述,按照文档教程自行学习)
文档推荐
学习新知识,有中文文档当然是最好的啦!
Vue Test Utils jest中文文档
组件挂载相关方法
shallowMount
shallowMount:
创建一个包含被挂载和渲染的 Vue 组件的 Wrapper。与之对应的还有一个mount。
shallowMount与mount的区别:
在文档中描述为"不同的是被存根的子组件",大白话就是shallowMount不会加载子组件,不会被子组件的行为属性影响该组件。
为什么使用shallowMount而不使用mount:
我认为单元测试的重点在"单元"二字,而不是"测试",想测试子组件再为子组件写对应的测试代码即可。
import { shallowMount } from '@vue/test-utils' import Foo from './Foo.vue' describe('Foo', () => { ? ? const wrapper = shallowMount(Foo) })
Wrapper(这里只记录一些我经常使用的)
Wrapper :Wrapper 是一个包括了一个挂载组件或 vnode,以及测试该组件或 vnode 的方法。 Wrapper.vm :这是该 Vue 实例。你可以通过 wrapper.vm 访问一个实例所有的方法和属性。 Wrapper.classes :返回是否拥有该class的dom或者类名数组。 Wrapper.find :返回第一个满足条件的dom。 Wrapper.findAll :返回所有满足条件的dom。 Wrapper.html :返回html字符串。 Wrapper.text :返回内容字符串。 Wrapper.setData :设置该组件的初始data数据。 Wrapper.setProps :设置该组件的初始props数据。 Wrapper.trigger :用来触发事件。<template> ?? ?<div class="jest"> ?? ??? ?<div class="name">{{name}}</div> ?? ??? ?<div class="name">{{name}}{{text}}</div> ?? ??? ?<div class="text" @click="add">{{text}}</div> ?? ?</div> </template> <script src="./script.js"> export default { ?? ?name:"Foo", ?? ?props:{ ?? ??? ?name:{ ?? ??? ??? ?type: String, ?? ??? ??? ?default: '王大大' ?? ??? ?} ?? ?}, ? ? data() { ? ? ? ? return { ? ? ? ? ? ? text: 123 ? ? ? ? } ? ? }, ? ? methods:{ ? ? ?? ?add(){ ?? ??? ??? ?this.text += 1 ?? ??? ?} ? ? } } </script>
import { shallowMount } from '@vue/test-utils' import Foo from './Foo.vue' describe('Foo', () => { ? ? const wrapper = shallowMount(Foo) ? ? console.log(Wrapper.classes())?? ?//['jest','name','test'] ? ? console.log(Wrapper.classes('jest'))?? ?//true ? ? console.log(Wrapper.find('name').text())?? ?//返回第一个class是name的dom的内容 ? 王大大 ? ? console.log(Wrapper.findAll('name'))?? ?//返回dom数组 ? ? console.log(Wrapper.findAll('name').at(0))?? ?//取dom数组中的第一个 ? ? Wrapper.setData({text : 1}) ? ? console.log(Wrapper.vm.text)?? ?//1 ? ? Wrapper.setProps({name : "李大大"}) ? ? console.log(Wrapper.vm.name)?? ?//李大大 ? ? Wrapper.find('text').trigger("click") ? ? console.log(Wrapper.vm.text) // 2 })
挂载选项
就是shallowMount或者mount的时候可以设置一些初始化内容。具体可以初始化的全部内容请查询文章开始的文档。
import { shallowMount } from '@vue/test-utils' import Foo from './Foo.vue' const wrapper = shallowMount(Foo, { ?? ?data() { ?? ??? ?return { ?? ??? ??? ?bar: 'my-override' ?? ??? ?} ? }, ? propsData: { ?? ??? ?msg: 'aBC' ? } ? mocks: { ? ? ? ? $route: { ? ? ? ? ? ? query: { ? ? ? ? ? ? ? ? aaa: '1', ? ? ? ? ? ? } ? ? ? ? }, ? ? ? ? $router: { ? ? ? ? ? ? push: jest.fn(), ? ? ? ? ? ? replace: jest.fn(), ? ? ? ? } ? ? } })
jest-api
匹配器
使用不同匹配器可以测试输入输出的值是否符合预期。
toBe :判断是否相等 toBeNull :判断是否为null toBeUndefined :判断是否为undefined toBeDefined :与上相反 toBeNaN :判断是否为NaN toBeTruthy :判断是否为true toBeFalsy :判断是否为false toContain :数组用,检测是否包含 toHaveLength :数组用,检测数组长度 toEqual :对象用,检测是否相等 toThrow :异常匹配(没用过)describe('Foo', () => { ?? ?expect(2 + 2).toBe(4) ?? ?expect(null).toBeNull() ?? ?expect(undefined).toBeUndefined() ?? ?let a = 1; ?? ?expect(a).toBeDefined() ?? ?a = 'ada'; ?? ?expect(a).toBeNaN() ?? ?a = true; ?? ?expect(a).toBeTruthy() ?? ?a = false; ?? ?expect(a).toBeFalsy() ?? ?a ?= [1,2,3]; ?? ?expect(a).toContain(2) ?? ?expect(a).toHaveLength(3) ?? ?a = {a:1}; ?? ?expect(a).toEqual({a:1}) })
mock函数
例如:在一个vue组件中,ajax请求、路由跳转是常常用到的,但是在单测代码中,我们并不能正确的知道他是否执行并达到了预期的效果,这时就需要mock函数。在上文挂载选项中的mocks.$router就是一种mock函数的应用实例。
mock函数自然是要使用该函数,下面是一些函数的常用匹配器
toBeCalledTimes :判断函数被执行的次数 toBeCalled :判断函数是否被执行<template> ?? ?<div class="jest" @click="go"></div> </template> <script src="./script.js"> export default { ?? ?name:"Foo", ? ? methods:{ ? ? ?? ?go(){ ?? ??? ??? ?this.$router.push({path:"/a"}) ?? ??? ?} ? ? } } </script>
import { shallowMount } from '@vue/test-utils' import Foo from './Foo.vue' const wrapper = shallowMount(Foo, { ? mocks: { ? ? ? ? $router: { ? ? ? ? ? ? push: jest.fn(), ? ? ? ? ? ? replace: jest.fn(), ? ? ? ? } ? ? } }) wrapper.find(“jest").trigger("click"); expect(wrapper.vm.$router.push).toBeCalled(); wrapper.find(“jest").trigger("click"); expect(wrapper.vm.$router.push).toBeCalledTimes(2);
promise模拟
jest.mock('@root/api'); //模拟api请求函数 import {getList} from '@root/api'; const listJson = JSON.parse(require('fs').readFileSync('./mock/getList.json')); //引入mock好的json数据 getList.mockResolvedValue(Promise.resolve(listJson)); //模拟promise返回 getList().then(res => { ?? ?expect(res).toEqual(listJson); })
为什么要使用单测
说了这么多,那为什么要使用单测呢。在看完上面的描述我想大家也是一头郁闷,单测有用吗?答案当然是有。下面举个例子:
<template> ?? ?<div class="jest"></div> </template> <script src="./script.js"> import {getList} from '@root/api'; export default { ?? ?name:"Foo", ? ? created(){ ? ? ?? ?getList() ? ? ?? ?.then(res => { ? ? ?? ??? ?this.initData(res) ? ? ?? ?}) ? ? }, ? ? methods:{ ?? ??? ?initData(data){ ?? ??? ??? ?data.name = '王大大'; ?? ??? ?} ?? ?} } </script>
import { shallowMount } from '@vue/test-utils' import Foo from './Foo.vue' const wrapper = shallowMount(Foo)
这时候就会报错data.name,因为data不一定有值。正确案例如下
<template> ?? ?<div class="jest"></div> </template> <script src="./script.js"> import {getList} from '@root/api'; export default { ?? ?name:"Foo", ? ? created(){ ? ? ?? ?getList() ? ? ?? ?.then(res => { ? ? ?? ??? ?this.initData(res) ? ? ?? ?}) ? ? }, ? ? methods:{ ?? ??? ?initData(data = {}){ ?? ??? ??? ?data.name = '王大大'; ?? ??? ?} ?? ?} } </script>
说白了就是让你的代码逻辑更符合预期结果。
总结
目前在vue中用到的一些基本知识都已经总结完了,如果以后在工作中使用了新的api,时间充裕的情况下我会持续更新。以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
查看更多关于vue中如何使用jest单元测试的详细内容...