Jest单元测试如何在每个用例中修改Vuex mock数据
单元测试动态修改Mock Vuex数据方案
问题根因
原有写法失效的核心原因是jest.mock的工厂函数在模块加载阶段就会执行,里面写死的getters是静态固定值:
- mock的getter返回值在模块初始化后就被固化,后续直接修改对象属性无法被Vue响应式系统捕获
- 把render逻辑全写在
beforeEach中,没有给单个测试用例留自定义store状态的入口 - 硬编码的getter值不支持按测试场景动态切换
实现方案
核心改造点只有3个:
- 把mock store的getters、commit等属性抽到测试文件外层的可变变量中,不要在mock工厂里写死固定值
- 让
useStore每次调用都返回最新的mock变量引用,而不是初始化时的静态对象 - 每个测试用例执行前重置默认mock状态,避免用例之间相互污染,渲染前直接修改mock值即可适配当前测试场景
改造后的测试代码示例
import { render, screen } from '@tests/app-test-utils' import ItemsDisplayer from './ItemsDisplayer.vue' import { capitalize } from '@/utils/capitalize' // 外层定义可变mock变量,支持每个用例单独修改 let mockStoreState: { getters: Record<string, any> commit: jest.Mock } jest.mock('vuex', () => ({ ...jest.requireActual('vuex'), // useStore每次调用返回最新的mock状态,而非静态写死的值 useStore: () => mockStoreState, })) describe('ItemsDisplayer', () => { // 每个用例执行前重置默认mock,避免用例间状态污染 beforeEach(() => { mockStoreState = { getters: { [`filters/get${capitalize('categories')}Many`]: [], }, commit: jest.fn(), } }) it('选中项为空时渲染-', async() => { render(ItemsDisplayer, { props: { type: 'categories', menuType: 'checkbox', items: [ { box_templates: "", id: "1", name: "Culture" }, { box_templates: "", id: "2", name: "Economy" }, { box_templates: "", id: "3", name: "Education" } ] } }) expect(await screen.findByText('-')).toBeInTheDocument() }) it('选中1项时渲染对应项名称', async() => { // 渲染前直接修改mock getters值即可,无需重写整个vuex mock mockStoreState.getters[`filters/get${capitalize('categories')}Many`] = ["1"] render(ItemsDisplayer, { props: { type: 'categories', menuType: 'checkbox', items: [ { box_templates: "", id: "1", name: "Culture" }, { box_templates: "", id: "2", name: "Economy" }, { box_templates: "", id: "3", name: "Education" } ] } }) expect(await screen.findByText('Culture')).toBeInTheDocument() }) it('选中全部时渲染all', async() => { mockStoreState.getters[`filters/get${capitalize('categories')}Many`] = 'all' render(ItemsDisplayer, { props: { type: 'categories', menuType: 'checkbox', items: [] } }) expect(await screen.findByText('all')).toBeInTheDocument() }) it('选中多项时渲染选中数量', async() => { mockStoreState.getters[`filters/get${capitalize('categories')}Many`] = ["1", "2"] render(ItemsDisplayer, { props: { type: 'categories', menuType: 'checkbox', items: [ { box_templates: "", id: "1", name: "Culture" }, { box_templates: "", id: "2", name: "Economy" } ] } }) expect(await screen.findByText('2')).toBeInTheDocument() }) })
额外优化建议
- 不要把render逻辑全写在
beforeEach里,单个测试用例的props、store状态存在差异时,直接在用例内执行render更灵活,也更方便排查问题 - 如果需要测试commit调用逻辑,直接在对应用例里断言
mockStoreState.commit的入参即可 - 如果后续需要测试radio类型的menuType,直接在对应用例里给
mockStoreState.getters添加对应key的返回值就行,不需要修改全局mock配置 - 如果不想手动mock vuex,也可以每个测试用例创建独立的真实Vuex store实例传入render选项,这种方式更贴近真实运行逻辑,适合复杂交互场景的测试。
内容的提问来源于stack exchange,提问作者Airea
相关产品推荐
相关产品推荐

