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

Jest同模块下jest.mock()部分mock单函数失效原因及解决

问题根本原因

这个现象的核心是JS模块的作用域引用规则,和你推测的「两个函数同属一个模块」方向一致,具体逻辑如下:

  • main.ts里定义的add、calculate首先是模块作用域下的本地函数,calculate内部调用add时,直接使用的是当前闭包内持有的原始add函数引用,完全不会经过模块的导出对象。
  • 你用jest.mock配合jest.requireActual的写法,本质是先拿到原模块的完整导出对象,再把导出对象上的add属性替换为自定义的mock函数。但这个修改只作用于导出对象,根本碰不到calculate闭包里存的那份原始add引用,所以执行calculate时,调用的还是未被mock的原始add,自然返回计算结果5,而不是你配置的17。

补充说明:你提到的jest.spyOn方案如果能生效,本质是你的TS/JS编译配置把模块内的函数调用编译成了exports.add()形式(即调用导出对象上的属性),这种场景下spyOn修改导出对象属性才能命中调用,否则spyOn同样会失效。

对应修复方案(坚持使用jest.mock方式的前提下)

核心思路是调整模块内的函数调用逻辑,让同模块内的互调走模块导出对象,而不是直接调用本地闭包内的函数,这样jest对导出对象的修改才能生效。
你可以修改main.ts的写法,参考如下实现:

// main.ts
export const add = (x: number, y: number): number => {
    return x + y;
}

export const minus = (x: number, y: number): number => {
    return x - y;
}

// 引入当前模块的导出对象
import * as self from './main';
export const calculate = (x: number, y: number, operator: string) => {
    let result = -1;
    switch (operator) {
        case '+':
            // 调用导出对象上的add,而非本地闭包持有的原始add
            result = self.add(x, y);
            break;
        case '-':
            result = self.minus(x, y);
            break;
    }
    return result;
}

修改完成后,你原来的测试代码不需要调整,运行时calculate就会调用到你mock的返回17的add函数。
如果不想修改业务源码,就只能用jest.spyOn配合对应的编译配置,或者拆分模块把add、minus抽到单独的文件里——这种场景下calculate调用add时走的是跨模块导入引用,jest.mock就可以正常拦截。

内容的提问来源于stack exchange,提问作者omer727

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 17:21:10