Jest中mock console.log失败:测试未捕获console.log调用问题
问题
我正在使用npm中的Jest进行测试,具体场景如下:
- 存在
TestScript.js文件,代码为:
function someComplexFunction() { console.log("some important message"); } module.exports = someComplexFunction
- 在
TestScript.test.js中编写测试代码:
const someComplexFunction = require("./TestScript") test('Console log should have been called', () => { const logSpy = jest.spyOn(console, 'log'); someComplexFunction(); expect(logSpy).toHaveBeenCalledWith('some important message'); logSpy.mockRestore(); });
运行npm test时测试失败,错误信息显示expect(jest.fn()).toHaveBeenCalledWith期望参数为"some important message",但调用次数为0。我尝试修改spyOn函数、换成console.warn测试均无效,请问哪里出错了,为何mock不生效?
解决方法
问题出在模块导入时机——你在创建spy之前就已经导入了TestScript.js,此时console.log的引用已经被固化在模块里,后续创建的spy无法覆盖它。
修正方案很简单:把模块导入语句移到spy创建之后,或者在每次测试前重新导入模块(配合jest.resetModules())。
方案1:延迟导入模块
修改测试文件代码:
test('Console log should have been called', () => { const logSpy = jest.spyOn(console, 'log'); // 延迟导入,确保spy已创建后再加载模块 const someComplexFunction = require("./TestScript"); someComplexFunction(); expect(logSpy).toHaveBeenCalledWith('some important message'); logSpy.mockRestore(); });
方案2:重置模块缓存(多测试用例场景)
如果需要在多个测试用例中重复使用,可以在测试前重置模块缓存:
beforeEach(() => { jest.resetModules(); // 清除已加载的模块缓存 }); test('Console log should have been called', () => { const logSpy = jest.spyOn(console, 'log'); const someComplexFunction = require("./TestScript"); someComplexFunction(); expect(logSpy).toHaveBeenCalledWith('some important message'); logSpy.mockRestore(); });
原理说明
Node.js模块是单例加载的,第一次导入TestScript.js时,console.log的引用会被保存在模块的作用域中。如果在导入后才创建spy,模块里的console.log还是原来的原生函数,不会指向你创建的spy,所以测试时无法捕获到调用记录。
把导入操作放在spy创建之后,模块加载时会使用已经被spy替换的console.log,这样就能正确捕获到函数的调用了。
内容的提问来源于stack exchange,提问作者Gajendra Kumar Sahu
相关产品推荐
相关产品推荐

