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

如何在Jest中保留模拟值?遇TypeError问题求解

解决Jest模拟Hook时保留原有模拟值的问题

我编写了全局Hook模拟代码:

jest.mock('hooks/limitIncrease', () => ({
  limitIncrease: jest.fn().mockImplementation(() => ({
    setReason: jest.fn(),
  })),
}));

在同一文件的某个独立测试用例中,我添加了这段代码来临时修改返回值:

(limitIncrease as jest.Mock).mockReturnValueOnce({
  handleSubmitNewLimit: handleSubmitNewLimitMock,
});

运行测试时却报错:TypeError: setReason is not a function

我自己有一个解决方案,但觉得不够优雅:

const mockedData = {
  setReason: jest.fn(),
};

jest.mock('hooks/limitIncrease', () => ({
  limitIncrease: jest.fn().mockImplementation(() => mockedData),
}));
(limitIncrease as jest.Mock).mockReturnValueOnce({
  ...mockedData,
  handleSubmitNewLimit: handleSubmitNewLimitMock,
});

错误原因

mockReturnValueOnce会完全替换掉mockImplementation预设的返回对象,新对象里没有setReason方法,导致调用时触发类型错误。

更优解决方案

方案一:复用默认模拟对象

不需要额外维护全局变量,直接从mock的结果中获取默认对象进行扩展:

// 全局Mock保持不变
jest.mock('hooks/limitIncrease', () => ({
  limitIncrease: jest.fn().mockImplementation(() => ({
    setReason: jest.fn(),
  })),
}));

// 测试用例中
(limitIncrease as jest.Mock).mockReturnValueOnce({
  ...(limitIncrease as jest.Mock).mock.results[0].value,
  handleSubmitNewLimit: handleSubmitNewLimitMock,
});

通过mock.results[0].value可以拿到mockImplementation返回的默认对象,再合并新属性即可保留原有方法。

方案二:用mockImplementationOnce替换原有实现

利用mockImplementationOnce临时重写实现逻辑,同时复用原实现的返回值:

// 全局Mock保持不变
jest.mock('hooks/limitIncrease', () => ({
  limitIncrease: jest.fn().mockImplementation(() => ({
    setReason: jest.fn(),
  })),
}));

// 测试用例中
(limitIncrease as jest.Mock).mockImplementationOnce(() => ({
  ...(limitIncrease as jest.Mock).mockImplementation(),
  handleSubmitNewLimit: handleSubmitNewLimitMock,
}));

这里直接调用原mockImplementation获取默认对象,再添加新方法,逻辑更清晰,也无需额外变量。

方案对比

你原来的方案需要维护一个全局的mockedData变量,上面两种方案都不需要额外维护状态,代码更简洁,也能避免全局变量带来的潜在问题。

内容的提问来源于stack exchange,提问作者Matheus Filype

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 01:02:22