在vue项目中,vuex是经常使用的一个插件,这个插件用来管理项目中的数据。那么在测试中又应该怎么测试vuex呢?接下来,就说一说测试vuex的方法。测试vuex的方法分为两种,一种是分别测试vuex的组成部分,一种是把vuex的store作为一个整体进行测试。
vuex由mutations、actions、getters、state组成,第一种方法就是分别对这些部分进行测试。
一个mutation测试的最终断言始终是要检查一个state对象是否被正确更改,因为这是mutation的目的。你可以将更改后的state对象视为一个mutation的输出。如果你的mutation没有改变state对象,那就说明你没有正确地使用它们。
import mutation from '../mutations'
describe('mutation',()=>{
test('setItems',()=>{
const items = [{id:1},{id:2}];
const state = {
items:[]
}
mutations.setItems(state,{items});
expect(state.items).toBe(items);
});
});
同mutation一样,Vuex getter也是普通的JavaScript函数。getter始终返回一个值,这样使要测试的内容变得简单化,你将始终断言getter函数的返回值。要测试getter,可以使用一个假的state对象调用getter函数,该state对象包含getter将使用的值,然后断言getter是否返回你期望的结果。
import getters from '../getters';
describe('getters',()=>{
test('displayItems',()=>{
const items = Array(21).fill().map((v,i)=> i);
// 构造一个假的state
const state = {
items
}
const result = getters.displayItems(state);
const expectedResult = item.slice(0,20);
expect(result).toEqual(expectedResult);
});
});
action使你能够异步提交mutation。通常,action会进行API调用并提交结果。因为action可以是异步的,并且可以发送HTTP请求,所以同mutation或getter相比,为action编写单元测试要更复杂。
要测试action,我们需要按照Vuex调用它的方式调用该函数,并断言该action是否按你的期望执行。通常,这意味着要利用模拟避免产生HTTP调用。
我们可以使用jest.mock()方法模拟请求。
import actions from '../actions'
import {fetchListData}from '../../api/api'
import flushPromises from 'flush-promises'
jest.mock('../../api/api')
describe('actions',()=>{
test('fetchListData',async ()=>{
expect.assertions(1)
const items= [{},{}]
const type = 'top'
fetchListData.mockImplentationOnce(calledWidth => {
return calledWith === type ? Promise.resolve(items) : Promise.resolve();
})
const context = {
commit:jest.fn()
}
actions.fetchListData(context,{type});
await flushPromises();
expect(context.commit).toHaveBeenCalledWith('setItems',{items});
});
})
这种方法是把vuex作为一个整体进行测试的方法。
要测试它,先在Vue构造函数上安装Vuex,再创建一个store并通过commit提交一个mutation。然后,你可以断言在提交mutation后state会发生变化。
import {cloneDeep} from 'lodash'
import {createLocalVue} from '@vue/test-utils'
import flushPromises from 'flush-promises';
import {createVuex} from 'vuex';
import {fetchListData} from '../../api/api'
jest.mock('../../api/api');
function createItems(){
const arr = new Array(22);
return arr.fill().map((item,i)=>{
return {
id:`${i}`,
name:'item'
}
});
}
describe('store',()=>{
test('fetchListData',async ()=>{
expect.assertions(1);
const items = createItems();
// 通过克隆得到store配置对象,避免测试用例间的干扰
const clonedStoreCofig(cloneDeep({}));
const store = createStore(clonedStoreConfig);
const type = 'top'
fetchListData.mockImplementation(calledType => {
return calledType === type ? Promise.resolve(items) :Promise.resolve();
});
store.dispatch('fetchListData',{type});
await flushPromisses();
expect(store.getters.displayItems).toEqual(items.slice(0,20));
});
});
为了能够测试组件中的vuex是否正常工作,我们需要先创建一个vuex的实例并传递给组件。
import {shallowMount,createLocalVue} from '@vue/test-utils'
import {createStore}from 'vuex'
import flushPromises from 'flush-promises'
import itemList from '../ItemList.vue'
import Item from '../../components/Item.vue'
const localVue = createLocalVue();
localVue.use(Vuex)
describe('ItemList.vue',()=>{
let storeOptions;
let store;
beforeEach(()=>{
storeOptions = {
getters:{
displayItems:jest.fn()
},
actions:{
fetchListData:jest.fn(()=>{
return Promise.resolve()
});
}
};
store = createStore(storeOptions);
});
test('render Items',()=>{
const $bar = {
start:()=>{},
finish:()=>{}
}
const items = [{},{},{}]
storeOptions.getters.displayItems.mockReturnValue(items);
const wrapper = shallowMount(ItemList,{
mocks:{$bar},
localVue,
store
});
const Items = wrapper.findAll(Item)
expect(Items).toHaveLength(items.length);
Items.wrappers.forEach((wrapper,i)=>{
expect(wrapper.vm.item).toBe(items[i]);
})
});
});