Jest spy的toHaveBeenCalled未检测到函数调用问题求助
问题原因及解决方案
核心问题
你的测试失败有两个关键原因:
- 模块内函数调用未经过导出引用
mainFunc内部直接调用的是本地定义的func1,而jest.spyOn(utils, 'func1')监听的是导出的func1引用。模块内部直接调用本地函数时,不会经过导出的绑定链路,所以 spy 无法捕获到调用行为——这就是为什么你能看到func1的日志,却断言失败的原因。 - 测试代码拼写错误
测试里的utils.mainFun('something')是笔误,应该是utils.mainFunc('something')(你提到能看到日志,推测实际运行时已修正,但这个细节需要注意)。
解决方案
方案一:不修改原代码,用 Jest Mock 重写模块(推荐)
通过手动 mock 整个模块,让mainFunc调用的是被 spy 包裹的func1,同时保留原函数逻辑:
// test.spec.js import * as utils from './MyFile.js'; // 手动mock模块,保留原功能并添加spy jest.mock('./MyFile.js', () => { const original = jest.requireActual('./MyFile.js'); return { ...original, func1: jest.fn(original.func1) }; }); it('Should trigger func1', () => { utils.mainFunc('something'); expect(utils.func1).toHaveBeenCalled(); expect(utils.func1).toHaveBeenCalledWith('something'); });
方案二:修改原代码的调用路径(不推荐,侵入业务代码)
让mainFunc通过导出对象调用func1,这样调用会经过导出绑定,spy 就能捕获:
// MyFile.js export const func1 = (arg1) => { console.log('inside func1'); // Do something } export const mainFunc = (mainArg) => { // 改为调用导出的func1 exports.func1(mainArg); }
方案三:重构模块(适合长期维护)
把func1等内部依赖函数抽离到单独的子模块,比如utils-internal.js,然后在MyFile.js中导入使用。测试时直接监听子模块的func1即可:
// utils-internal.js export const func1 = (arg1) => { console.log('inside func1'); // Do something } // MyFile.js import { func1 } from './utils-internal.js'; export const mainFunc = (mainArg) => { func1(mainArg); } // test.spec.js import * as utils from './MyFile.js'; import * as internalUtils from './utils-internal.js'; it('Should trigger func1', () => { const spy = jest.spyOn(internalUtils, 'func1'); utils.mainFunc('something'); expect(spy).toHaveBeenCalled(); });
内容的提问来源于stack exchange,提问作者physicsboy
相关产品推荐
相关产品推荐

