Jest中mock函数返回的嵌套get方法时spyOn报错如何解决
问题根因
报错的核心原因有两个:
jest.mock的工厂返回值结构错误:你写的mock工厂返回的函数执行后返回了带default属性的对象,但业务代码是默认导入axiosInstanceWrapper,导入的变量本身就是mock工厂返回的函数,调用该函数应该直接返回带get方法的实例,不需要嵌套default层。spyOn的监听目标完全错误:get是axiosInstanceWrapper()执行后返回的实例上的方法,既不挂载在axiosInstanceWrapper函数本身,也不存在于它的default属性上,直接对axiosInstanceWrapper.get做监听自然会拿到undefined。
正确实现方案
方案1:直接在mock模块时定义可复用的mock方法(推荐)
先把实例上的get抽成独立的mock函数引用,方便后续设置返回值、做调用断言,代码示例:
import axiosInstanceWrapper from './axios-instance-wrapper'; // 提前定义mock的get方法,方便后续用例内操作 const mockGet = jest.fn(); // 修正mock工厂的返回结构 jest.mock('./axios-instance-wrapper', () => { // 默认导入的axiosInstanceWrapper就是这个函数,调用后直接返回带get的mock实例 return jest.fn(() => ({ get: mockGet })); }); // 每个用例执行前清空mock记录,避免用例间互相干扰 beforeEach(() => { jest.clearAllMocks(); }); test('正确mock api.get返回值', () => { // 设置get方法的resolve返回值 mockGet.mockResolvedValue({ data: { customer: { subscriptionContracts: [], pageInfo: { hasNextPage: false, hasPreviousPage: false, } } } }); // 此处执行业务逻辑,例如调用封装了api.get的业务函数 // const result = await 你的业务方法(); // 可额外断言get的入参是否符合预期 // expect(mockGet).toHaveBeenCalledWith(MY_URL, myParams); });
方案2:拿到mock实例后用spyOn监听
如果你更习惯用spyOn的写法,需要先拿到axiosInstanceWrapper执行返回的实例,再对实例上的get做监听:
import axiosInstanceWrapper from './axios-instance-wrapper'; jest.mock('./axios-instance-wrapper', () => { return jest.fn(() => ({ get: () => {} // 先给一个空函数占位,spyOn才能挂载 })); }); test('spyOn写法实现', () => { // 先拿到mock返回的实例 const mockApiInstance = axiosInstanceWrapper({}); // 对实例上的get做监听和返回值mock const getSpy = jest.spyOn(mockApiInstance, 'get').mockResolvedValue({ data: { customer: { subscriptionContracts: [], pageInfo: { hasNextPage: false, hasPreviousPage: false, } } } }); // 后续执行业务逻辑、做断言即可 });
注意事项
如果你的业务代码里const api = axiosInstanceWrapper({})是写在模块顶层的,需要注意mock的生效时机:必须在导入业务模块之前完成mock注册,否则业务模块初始化时拿到的是真实的axiosInstanceWrapper,会导致mock失效。遇到这种场景可以在每个用例前重置模块,再动态导入业务模块:
beforeEach(() => { jest.resetModules(); jest.clearAllMocks(); }); test('顶层初始化api的场景处理', () => { mockGet.mockResolvedValue(/* 你需要的返回值 */); // 重置模块后再动态导入业务模块,会自动使用已mock的axiosInstanceWrapper初始化api const businessModule = require('./你的业务文件路径'); // 执行业务逻辑完成测试 // await businessModule.你的业务方法(); });
内容的提问来源于stack exchange,提问作者adam8810
相关产品推荐
相关产品推荐

