Jest spy未初始化 Mock函数不生效问题排查
问题原因
jest.spyOn语法错误:第一个参数要求传入实际导入的模块对象,你传入了字符串形式的变量名'Module2Handler',直接导致spy没有挂载到正确的模块导出对象上。- 核心引用问题:Module B 中
function2是直接调用同文件内闭包作用域里的原始function3,不是通过模块导出对象调用。你通过spyOn替换的只是模块导出对象上的function3引用,function2内部根本访问不到这个被替换的方法,自然不会触发mock逻辑。 - 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
相关产品推荐
相关产品推荐

