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

Vue Test Utils:如何动态Mock带参数的命名空间Getter返回值

问题描述

需要Mock Vuex命名空间app下的带参数Getter myGetter,使其动态返回测试参数,以此控制页面元素的可见性。原Getter为柯里化结构,目前尝试的多种Mock方式均未成功。

原Getter代码(位于app模块)

const getters = {
  myGetter:
    (state) =>
    (getterArg) => {
      return state.someStateVariable === true
        ? valueForTrue
        : valueForFalse;
    }
};

测试代码及失败尝试

import { cloneDeep }  from "lodash";
import { createLocalVue, shallowMount } from "@vue/test-utils";
import MyComponent from "@/views/MyComponent.vue";
import { storeConfig } from "@/store";
import Vuex from "vuex";
   
describe("My test", () => {
  let localVue;
  let store;
  let wrapper;

  beforeEach(() => {
    localVue = createLocalVue();
    localVue.use(Vuex);
  });

  test.each([[false], [true]])(
    "Test param: '%s'",
    (testParam) => {
      store = new Vuex.Store({
        modules: {
          app: {
            namespaced: true,
            ...cloneDeep(storeConfig.modules.app),
            state: {
              ...cloneDeep(storeConfig.modules.app.state),
            },
            getters: {
              ...cloneDeep(storeConfig.modules.app.getters),
              // 已定义getter,但未使用测试参数
              // myGetter: jest.fn().mockReturnValue(jest.fn())

              // 带Mock返回值的getter变体(测试失败)
              // myGetter: jest.fn().mockReturnValue(jest.fn().mockReturnValue(testParam))

              // 带组件传入参数和Mock返回值的getter变体(测试失败)
              // myGetter: jest.fn("getterArg").mockReturnValue(jest.fn().mockReturnValue(testParam))
            }
          }
        }
      });

      wrapper = shallowMount(MyComponent, {
        localVue,
        store
      });

      expect(wrapper.find("#my-element").exists()).toBe(testParam);
    }
  );
});

额外失败尝试(创建wrapper后修改)

// 测试失败,getter未定义
Object.defineProperty(wrapper.vm, "app/myGetter", {
  value: () => {
    return testParam;
  }
});

// 测试失败,getter未定义
Object.defineProperty(wrapper.vm, "app/myGetter", {
  value: ("getterArg") => {
    return testParam;
  }
});

解决方案

原Getter是柯里化函数((state) => (getterArg) => 返回值),Mock时必须匹配这个嵌套函数结构,以下是两种可行方案:

方案1:直接定义匹配结构的函数(最简方式)

在创建store时,重写myGetter为忽略参数、直接返回测试参数的柯里化函数:

store = new Vuex.Store({
  modules: {
    app: {
      namespaced: true,
      ...cloneDeep(storeConfig.modules.app),
      state: {
        ...cloneDeep(storeConfig.modules.app.state),
      },
      getters: {
        ...cloneDeep(storeConfig.modules.app.getters),
        // 核心:返回嵌套函数,最终返回测试参数
        myGetter: () => () => testParam
      }
    }
  }
});

方案2:使用jest.fn()模拟(支持调用断言)

如果需要验证myGetter的调用情况(比如调用次数、传入参数),可以用jest模拟嵌套函数:

getters: {
  ...cloneDeep(storeConfig.modules.app.getters),
  myGetter: jest.fn().mockReturnValue(jest.fn().mockReturnValue(testParam))
}

注意:确保测试代码中只保留这一行myGetter定义,避免多定义冲突导致失败。

为什么修改vm属性的方式失败?

Vuex命名空间Getter不会直接挂载到组件实例vm上,而是通过$store.getters['app/myGetter']访问。如果必须在创建wrapper后修改,可以直接操作store并强制组件更新:

// 修改store中的getter
store.getters['app/myGetter'] = () => testParam;
// 触发组件重新渲染
wrapper.vm.$forceUpdate();

不过优先推荐在创建store时完成Mock,避免状态不一致问题。


内容的提问来源于stack exchange,提问作者Growth Mindset

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 04:35:27