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

Jest调用mockRestore后跨describe块jest.mock失效问题

问题根因

测试失效核心是API误用+mock写法问题:

  • 第一个describe块的afterEach中调用了jest.resetAllMocks(),这个API会把所有mock函数的实现重置为返回undefined的空函数,直接清空了你在jest.mock中定义的SQS构造逻辑、deleteMessage方法逻辑,导致后续测试块拿到的SQS实例没有预设mock实现,走了真实SDK逻辑触发超时。
  • 原mock写法中SQS实例是在构造函数调用时动态生成的,一旦被reset后,后续新建SQS实例拿到的方法就是空函数,无法自动恢复最初写的mock逻辑。
  • 全局调用jest.restoreAllMocks()/jest.resetAllMocks()会无差别影响所有mock,包括你不想改动的AWS SDK模块级mock。
修复方案

按照以下步骤调整即可满足所有测试需求:

  • 替换全局重置类API:把会清空mock实现的jest.resetAllMocks()换成仅清空调用记录、不改动mock实现的jest.clearAllMocks()做用例间的状态隔离。
  • 调整AWS SDK mock结构:把SQS mock实例、deleteMessage相关逻辑抽到jest.mock外层作为固定引用,保证即使清空调用记录,mock实现也不会丢失。
  • 单独管理ingestAndSave的spy:仅对这个spy做挂载、恢复操作,不触碰AWS SDK的模块级mock。

修复后完整测试代码

const ingest = require('./ingest')
const TEST_CONSTANTS = require('../../../tests/constants')

// 提前定义全局唯一的SQS mock引用,避免重置后丢失实现
const mockDeleteMessagePromise = jest.fn().mockImplementation(() => {
  console.log("MOCK DELETE MESSAGE FUNCTION");
  return {}
})
const mockSqsInstance = {
  deleteMessage: jest.fn(() => ({
    promise: mockDeleteMessagePromise
  }))
}

// 模块级mock AWS SDK,SQS构造函数固定返回提前定义的mock实例
jest.mock('aws-sdk', () => {
  return {
    config: {
      update: jest.fn()
    },
    SQS: jest.fn(() => mockSqsInstance)
  }
});


describe("FUNCTION: ingest", () => {
  let ingestAndSaveFunctionSpy
  beforeEach(()=> {
    // 每个用例执行前挂载ingestAndSave的mock,清空所有mock的调用记录
    ingestAndSaveFunctionSpy = jest.spyOn(ingest, 'ingestAndSave').mockResolvedValue()
    jest.clearAllMocks()
  })

  test("ingestAndSave will be called two times when event has two Records", async () => {
    await ingest.ingest(TEST_CONSTANTS.sqsIngestEventMessageWithTwoRecords)
    expect(ingestAndSaveFunctionSpy).toHaveBeenCalledTimes(2) 
  })
  
  afterEach(() => {
    // 仅恢复ingestAndSave的原始实现,不改动AWS SDK的mock
    ingestAndSaveFunctionSpy.mockRestore()
  })
  // 移除原afterAll中全局调用restoreAllMocks的逻辑
})


describe("FUNCTION: ingestAndSave", () => {
  let validParams = {camera: TEST_CONSTANTS.validCameraObject, sourceQueueURL:"httpexamplecom", receiptHandle: "1234abcd"}

  beforeEach(() => {
    // 每个用例前清空调用记录,保证断言计数准确
    jest.clearAllMocks()
  })

  test("Will call deleteMessage once when given valid paramters", async () => {
    await ingest.ingestAndSave(validParams)
    expect(mockDeleteMessagePromise).toHaveBeenCalledTimes(1)
  })
  /** snip other tests */
})

Jest mock相关API核心区别,避免后续踩坑:

  • jest.clearAllMocks():仅清空所有mock的调用记录、入参记录、返回结果记录,不修改mock原有实现,是跨用例做状态隔离的首选
  • jest.resetAllMocks():清空调用记录的同时,会把所有mock的实现重置为返回undefined的空函数,会直接抹掉你手动写的mock逻辑,非特殊场景不要全局调用
  • jest.restoreAllMocks():仅对通过jest.spyOn创建的mock生效,会把spy替换回原始实现,对jest.mock定义的模块级mock没有恢复效果,但全局调用容易误伤其他spy,建议对单个spy手动调用mockRestore()即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 06:51:22