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

Jest单元测试中重写桩(stub)函数mock行为未按预期生效

问题原因

你的代码不生效有四个核心问题:

  • jest.mock 会被Jest自动提升到文件最顶部执行,测试运行阶段(比如beforeAll钩子中)再次调用jest.mock不会触发模块重新替换,完全无效。
  • 你在error场景的beforeEach里提前执行了控制器方法,此时还没修改mock行为,拿到的永远是默认mock的返回值。
  • 你写的二次mock返回结构和原有mock不匹配:原有手动mock导出的是构造函数形式的ShipmentSummaryService,二次mock直接返回了带方法的普通对象,就算mock生效也会导致Nest依赖注入失败。
  • 异步方法抛错的断言写法错误,同步写法的expect(() => fn()).toThrow()捕获不到异步抛出的异常。
修复方案

不需要重新mock整个模块,你已经通过moduleRef.get()拿到了注入的mock服务实例,直接修改实例上对应方法的mock实现即可,这是Jest手动mock场景下切换测试行为的标准做法。

  1. 保留你现有的顶层jest.mock声明和__mocks__文件夹下的mock服务实现,不需要改动。
  2. 重写error场景的测试块代码如下:
describe('error scenario', () => {
  beforeAll(() => {
    // 直接修改mock服务实例上的方法行为,覆盖默认的ResolvedValue配置
    shipmentSummaryService.getAvailableShipmentModes.mockRejectedValue(new Error('Test error'));
  });

  afterAll(() => {
    // 测试完成后恢复默认mock实现,避免影响其他测试块
    shipmentSummaryService.getAvailableShipmentModes.mockResolvedValue(validModeDropdown());
  });

  test('throws an error', async () => {
    // 异步抛错需要用rejects配合await断言
    await expect(shipmentSummaryController.getAllShipmentModes('256')).rejects.toThrow('Test error');
  })
})
额外说明
  • 不要在测试运行阶段(钩子、测试用例内)调用jest.mock,该API仅在文件加载初始化阶段生效。
  • 你顶层beforeEach里的jest.clearAllMocks()只会清空mock的调用记录、mock实例的调用状态,不会重置你配置的mockResolvedValue/mockRejectedValue行为,所以在单独测试块里修改mock行为后,记得在块结束后恢复默认值,避免测试用例之间互相污染。
  • 如果需要在单个测试用例里修改mock行为,直接在test块内调用对应mock方法的mockReturnValue/ mockResolvedValue即可,作用范围可以通过beforeEach/ afterEach灵活控制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 16:18:21