You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 23:36:35