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

Jest如何Mock模块内单个函数并断言其调用参数

问题根因

你写的代码有两个核心错误:

  • 导入语法错误:你的模块是命名导出(export const f/g/h),没有默认导出,你写的import f, g, h from 'module'会尝试读取模块的默认导出作为f,本身就会导致f引用错误,拿不到mock后的函数。
  • Mock引用与作用域问题:你在jest.mock工厂函数内部创建的jest.fn()是工厂的局部变量,测试用例中没有这个函数的引用,自然无法断言调用;同时没有标记__esModule: true的话,Jest处理ES模块时会出现引用绑定异常,导致模块内部的g、h始终调用闭包内的原始f,不会走你mock的版本。
解决方案

以下两种方案都可以实现需求,根据场景选择即可。

方案1:使用jest.spyOn(推荐,灵活度最高)

这个方案不需要提前固定mock实现,每个用例可以按需决定是否保留f的原始逻辑,也不需要额外维护mock变量的引用。

// 注意:用命名空间导入整个模块,不要用默认导入
import * as targetModule from './your-module-path'

// mock模块时默认保留所有函数的原始实现
jest.mock('./your-module-path', () => {
  const originalModule = jest.requireActual('./your-module-path')
  return {
    __esModule: true, // 必须加,标记为ES模块避免引用异常
    ...originalModule
  }
})

// 每个用例执行后自动恢复所有mock的原始实现,避免用例间污染
afterEach(() => {
  jest.restoreAllMocks()
})

test('g 调用f时传入参数正确', () => {
  // 替换模块导出的f为mock函数,如果不需要f执行原始逻辑,可链式调用.mockImplementation(() => {})
  const mockF = jest.spyOn(targetModule, 'f')

  // 执行被测函数
  targetModule.g()

  // 断言f被调用时的入参符合预期
  expect(mockF).toHaveBeenCalledWith(/* 这里写你预期的入参,比如 'test', 123 等 */)
})

test('h 调用f时传入参数正确', () => {
  const mockF = jest.spyOn(targetModule, 'f').mockImplementation(() => {})
  targetModule.h()
  expect(mockF).toHaveBeenCalledWith(/* 预期入参 */)
})

方案2:顶层声明Mock函数(适合全局统一Mock f的场景)

如果你所有用例都需要mock f,不需要保留f的原始实现,可以直接在顶层声明mock函数,在mock工厂里直接替换。

// 顶层提前声明mock f,整个测试文件都可以拿到这个引用
const mockF = jest.fn()
// 命名空间导入模块
import * as targetModule from './your-module-path'

jest.mock('./your-module-path', () => {
  const originalModule = jest.requireActual('./your-module-path')
  return {
    __esModule: true,
    ...originalModule,
    f: mockF // 直接用提前声明的mockF替换原始f
  }
})

// 每个用例前清空mock的调用记录,避免上一个用例的调用记录影响断言
beforeEach(() => {
  mockF.mockClear()
})

test('g 调用f时传入参数正确', () => {
  targetModule.g()
  expect(mockF).toHaveBeenCalledWith(/* 预期入参 */)
})

test('h 调用f时传入参数正确', () => {
  targetModule.h()
  expect(mockF).toHaveBeenCalledWith(/* 预期入参 */)
})
注意事项
  • 不要用默认导入的方式导入只有命名导出的模块,否则会出现引用undefined的问题。
  • 如果你的项目用TypeScript,给jest.spyOn传入方法的时候可能需要做类型断言,不影响运行时逻辑。
  • 如果需要f在mock时还能执行原始逻辑,不要加mockImplementation,spyOn默认会保留原始实现,同时记录调用参数和次数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 10:39:26