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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 19:12:56