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

Jest spy的toHaveBeenCalled未检测到函数调用问题求助

问题原因及解决方案

核心问题

你的测试失败有两个关键原因:

  1. 模块内函数调用未经过导出引用
    mainFunc 内部直接调用的是本地定义的 func1,而 jest.spyOn(utils, 'func1') 监听的是导出的func1引用。模块内部直接调用本地函数时,不会经过导出的绑定链路,所以 spy 无法捕获到调用行为——这就是为什么你能看到func1的日志,却断言失败的原因。
  2. 测试代码拼写错误
    测试里的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 13:26:00