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

同一文件内函数Mock失效:测试中Mock可见但组件仍调用原函数

同一文件内组件调用的方法Mock失效问题

问题场景

尝试Mock被测组件调用的同文件方法,但Mock不生效:组件依然调用原函数,断言失败,原函数的日志也会输出。

被测文件代码

export function trackErrors() {
    console.log("This SHOULD NOT BE SEEN ON tests");
    // 目前运行测试时这条日志会被打印
}

// 待测试组件
export const form = () => {
    return <FormComponent callback={trackErrors} />
}

测试代码(Mock方案)

jest.mock('./testedFile', () => {
    const actualModule = jest.requireActual('./testedFile')

    return new Proxy(actualModule, {
        get: (target, property) => {
            switch (property) {
                case 'trackErrors': {
                    return jest.fn()
                }
                default: {
                    return target[property]
                }
            }
        },
    })
})

import * as SModule from "./testedFile";

it.only("Calls trackErrors", async () => {
      const { getByTestId } = render(<SModule.form />);

      await typeEmail(getByTestId, "abcd");

      await waitFor(() => {
        expect(SModule.trackErrors).toHaveBeenCalledTimes(1);
      });
});

问题现象

  • 打印SModule.trackErrors能看到是Mock函数,但断言调用次数为0失败
  • 原函数的console.log输出可见,说明组件实际调用的是未Mock的原函数
  • 尝试spyOn方案,结果完全相同

原因分析

核心问题是模块内直接引用:组件form定义时,直接通过本地标识符trackErrors绑定了原函数,而非通过模块导出的引用。Jest的Mock仅能替换模块对外导出的内容,无法修改模块内部已经建立的直接引用关系。

解决方案

方案1:通过模块自身引用导出的方法

修改被测文件,让组件通过模块导出对象引用trackErrors,这样Mock替换导出后,组件会自动使用Mock版本:

// ES模块写法:导入自身模块
import * as self from './testedFile';

export function trackErrors() {
    console.log("This SHOULD NOT BE SEEN ON tests");
}

export const form = () => {
    return <FormComponent callback={self.trackErrors} />
}

如果是CommonJS环境,替换为module.exports.trackErrors即可。

方案2:将方法抽离到独立模块

把trackErrors移到单独模块,被测文件和测试都导入该模块,Mock这个独立模块即可生效:

// utils/trackErrors.js
export function trackErrors() {
    console.log("This SHOULD NOT BE SEEN ON tests");
}

// testedFile.js
import { trackErrors } from './utils/trackErrors';

export const form = () => {
    return <FormComponent callback={trackErrors} />
}

测试代码修改为:

jest.mock('./utils/trackErrors', () => ({
    trackErrors: jest.fn()
}));

import * as TrackUtils from './utils/trackErrors';
import { form } from './testedFile';

it.only("Calls trackErrors", async () => {
    const { getByTestId } = render(<form />);
    await typeEmail(getByTestId, "abcd");
    await waitFor(() => {
        expect(TrackUtils.trackErrors).toHaveBeenCalledTimes(1);
    });
});

方案3:使用Jest rewire(仅CommonJS)

如果项目基于CommonJS,可以用jest-rewire修改模块内部变量,但ES模块不支持这种方式,仅作为临时解决方案,不推荐长期使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 05:25:40