共计 3309 个字符,预计需要花费 9 分钟才能阅读完成。
在 Vue 项目
中测试组件时会引用全局组件,那么如何处理这些全局组件呢?还有 Vue
中比较重要的一个点就是 Vuex
如何进行测试?
1. 测试时使用 VueRouter
1.1 存根
在你的组件中引用了全局组件 router-link
或者 router-view
组件时,我们使用 shallowMount
来渲染时会提示无法找到这两个组件,我们可以使用存根的方式 mock
掉相关的组件。
<template> | |
<div> | |
<h1> 当前路由:{{this.$route.path}}</h1> | |
<router-link to="/"> 首页 </router-link> | |
<router-link to="/about"> 关于页面 </router-link> | |
<router-view></router-view> | |
</div> | |
</template> |
import Nav from "@/components/Nav.vue"; | |
import {shallowMount} from "@vue/test-utils"; | |
it("测试 Nav 组件", () => { | |
let wrapper = shallowMount(Nav,{ | |
// 忽略这两个组件 | |
stubs:['router-link','router-view'], | |
mocks:{ // mock 一些数据传入到 Nav 组件中 | |
$route:{path:'/'} | |
} | |
}); | |
expect(wrapper.find('h1').text()).toContain('/') | |
}); |
同理:我们可以
mock
掉一些全局组件,也可以mock
一些参数传入到组件中。
1.2 安装 VueRouter
我们可以也创建一个 localVue
来安装 VueRouter, 传入到组件中进行渲染。
安装 Vue Router
之后 Vue 的原型上会增加 $route
和 $router
这两个只读属性。所以不要挂载到基本的 Vue 构造函数上,同时也不能通过 mocks
参数重写这两个属性
const localVue = createLocalVue(); | |
localVue.use(VueRouter); | |
it("测试 Nav 组件", () => { | |
let router = new VueRouter({ | |
routes:[{path:'/',component:Home}, | |
{path:'/about',component:About} | |
] | |
}); | |
let wrapper = mount(Nav,{ | |
localVue, | |
router | |
}); | |
router.push('/about'); | |
expect(wrapper.find('h1').text()).toMatch(/about/) | |
}); |
2.Vuex 的测试
我们通过一个 计数器
的例子来掌握如何测试 vuex。
<template> | |
<div> | |
{{this.$store.state.number}} | |
<button @click="add(3)"> 添加 </button> | |
</div> | |
</template> | |
<script> | |
import {mapActions} from 'vuex'; | |
export default { | |
methods:{...mapActions({'add':'increment'}) | |
} | |
} | |
</script> |
编写store/index.js
import Vue from 'vue' | |
import Vuex from 'vuex' | |
import config from './config' | |
Vue.use(Vuex) | |
export default new Vuex.Store(config) |
编写store/mutations.js
export default {increment(state,count){state.number+=count} | |
} |
编写store/actions.js
export default {increment({ commit}, count) {setTimeout(() => {commit("increment", count); | |
}, 1000); | |
} | |
}; |
编写store/config.js
import mutations from "./mutations"; | |
import actions from "./actions"; | |
export default { | |
state: {number: 0}, | |
mutations, | |
actions | |
}; |
这里我们就不过多详细讲解 vuex 的执行过程了,直接开始测试啦!
2.1 单元化测试 store
我们可以直接把 store
中的方法一一进行单元测试。
就是逐个测试函数,但是需要用 mock 来 commit
和 dispatch
方法。
import mutations from '../mutations'; | |
import actions from '../actions'; | |
jest.useFakeTimers(); | |
it('测试 mutation',()=>{const state = {number:0}; | |
mutations.increment(state,2); | |
expect(state.number).toBe(2); | |
}); | |
it('测试 action',()=>{let commit = jest.fn(); | |
actions.increment({commit},2); | |
jest.advanceTimersByTime(2000); | |
expect(commit).toBeCalled(); | |
expect(commit.mock.calls[0][1]).toBe(2); | |
}); |
2.2 测试运行的 store
就是产生一个 store
进行测试,好处是不需要 mock
任何方法。
import Vuex from 'vuex'; | |
import {createLocalVue} from '@vue/test-utils' | |
import config from '../config'; | |
jest.useFakeTimers(); | |
it('测试是否可以异步增加 1',()=>{let localVue = createLocalVue(); | |
localVue.use(Vuex); | |
let store = new Vuex.Store(config); // 创建一个运行 store | |
expect(store.state.number).toBe(0); | |
store.dispatch('increment',2); | |
jest.advanceTimersByTime(2000); // 前进 2s | |
expect(store.state.number).toBe(2); | |
}); |
config 文件最好每次测试时克隆一份,保证每个用例间互不干扰!
2.3 测试组件中的 Vuex
mock store
传入组件中,看函数是否能够如期调用。
import Vuex from 'vuex'; | |
import Counter from '@/components/Counter'; | |
import {createLocalVue,shallowMount} from '@vue/test-utils' | |
let localVue = createLocalVue(); | |
localVue.use(Vuex); | |
let store; | |
let actions; | |
beforeEach(()=>{ | |
actions = {increment:jest.fn() | |
} | |
store = new Vuex.Store({ | |
actions, | |
state:{}}); | |
}); | |
it('测试组件中点击按钮 是否可以 1',()=>{ | |
let wrapper = shallowMount(Counter,{ | |
localVue, | |
store | |
}); | |
wrapper.find('button').trigger('click'); | |
// 测试 actions 中的 increment 方法是否能正常调用 | |
expect(actions.increment).toBeCalled();}) |
到这里
Vuex
测试的方式我们就讲解完毕了,其实前端自动化测试并没有想象中的难,大家多多练习就可以完全掌握啦!
往期回顾:
前端自动化测试(一)
前端自动化测试(二)
前端自动化测试(三)
希望大家可以关注公众号【前端优选】,有任何想法和意见欢迎讨论交流!连续四天的连载到这里先要告一段落了,祝大家中秋节快乐!