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

Jest spy未初始化 Mock函数不生效问题排查

问题原因
  1. jest.spyOn 语法错误:第一个参数要求传入实际导入的模块对象,你传入了字符串形式的变量名 'Module2Handler',直接导致spy没有挂载到正确的模块导出对象上。
  2. 核心引用问题:Module B 中 function2 是直接调用同文件内闭包作用域里的原始 function3,不是通过模块导出对象调用。你通过spyOn替换的只是模块导出对象上的function3引用,function2内部根本访问不到这个被替换的方法,自然不会触发mock逻辑。
  3. mock方法使用错误:function3 是同步返回布尔值的函数,你用了mockResolvedValue,该方法会把函数包装为返回Promise的异步函数,就算spy生效,if(function3())判断的是Promise对象,永远为truthy,逻辑完全不符合预期。
解决方案

方案1:调整Module B内部调用方式(改造成本最低)

修改Module B中function2对function3的调用路径,改为通过模块导出对象调用,这样spyOn替换导出对象方法时,function2就能拿到被mock后的方法。
修改Module B代码:

const function2 = ()=>{
  //Calculations
  // 改为调用模块导出对象上的function3,不要直接调用内部声明的函数
  if(module.exports.function3()){
    //Transform
  }
  return obj;
}

const function3=()=>{
  return true/false;
}

export{function2,function3}

同时修正测试代码:

import * as Module2Handler from '../module2'
import * as Module1Handler from '../module1'

describe('Test for modules 1',()=>{
  let function3Spy;
  beforeEach(() => {
    // 第一个参数传入实际导入的模块对象,禁止传字符串
    function3Spy = jest.spyOn(Module2Handler,'function3');
  })
  afterEach(() => {
    // 每个用例执行完恢复原始实现,避免用例间污染
    function3Spy.mockRestore();
  })

  it('Return object with property a',async()=>{
    // 同步函数用mockReturnValue,不要用mockResolvedValue
    function3Spy.mockReturnValue(true);
    expect(await Module1Handler.function1({x:'123'})).toMatchObject({a:1})
    expect(function3Spy).toBeCalledTimes(1);
  })
})

方案2:直接mock整个Module B(无需修改业务代码)

如果不想调整业务代码的调用逻辑,可以在测试层直接mock整个Module B,手动接管两个导出函数的实现,让Module A导入的function2直接调用你mock版本的function3。
测试代码写法:

import * as Module1Handler from '../module1'
// 全量mock module2
jest.mock('../module2', () => {
  const originalModule = jest.requireActual('../module2');
  return {
    ...originalModule,
    function3: jest.fn(originalModule.function3)
  }
});
const Module2Handler = require('../module2');

describe('Test for modules 1',()=>{
  beforeEach(() => {
    jest.clearAllMocks();
  })
  it('Return object with property a',async()=>{
    Module2Handler.function3.mockReturnValue(true);
    expect(await Module1Handler.function1({x:'123'})).toMatchObject({a:1})
    expect(Module2Handler.function3).toBeCalledTimes(1);
  })
})

方案3:依赖注入(适合长期维护的项目)

给function2增加可选依赖参数,支持外部传入自定义的判断函数,测试时直接传入mock函数即可,完全不需要做模块级别的mock:
修改Module B代码:

// 支持传入自定义的判断函数,默认使用内部实现的function3
const function2 = (params, customFunc3 = function3)=>{
  //Calculations
  if(customFunc3()){
    //Transform
  }
  return obj;
}

测试代码无需spyOn,直接传参即可:

it('Return object with property a',async()=>{
  const mockFunc3 = jest.fn().mockReturnValue(true);
  // Module A调用function2时透传mock函数即可
  expect(await Module1Handler.function1({x:'123'}, mockFunc3)).toMatchObject({a:1})
  expect(mockFunc3).toBeCalledTimes(1);
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 16:54:08