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

Jest import导入被mock模块调用mockImplementation报错但require正常,spyOn如何实现同等效果

报错原因

核心是CommonJS与ES模块的导入行为差异导致:

  • require导入时会直接拿到jest.mock工厂函数返回的完整对象,其中execSync就是你声明的jest.fn()实例,因此可以正常调用mockImplementation方法。
  • 使用ES模块import语法时,Jest会自动触发ES模块兼容逻辑,给CommonJS模块包装一层标准ES模块结构。如果jest.mock的返回值没有标注__esModule: true,解构导入的execSync就不是你创建的mock函数,自然不存在mockImplementation方法。
  • 额外注意:直接使用import { execSync } from 'child_process'解构导入拿到的是函数的值拷贝,只有通过模块命名空间对象访问的属性引用,才能正确指向mock实例。

使用ES import的解决方法

有两种方案可以替换require语法正常使用import:

方案1:使用命名空间导入

不直接解构,导入完整模块命名空间对象访问mock方法:

jest.mock('child_process', () => {
  return {
    execSync: jest.fn(),
  };
});

import * as childProcess from 'child_process';
childProcess.execSync.mockImplementation(() => {
  return something;
});

方案2:给mock工厂加ES模块标记

在jest.mock的返回值中添加__esModule: true,告知Jest这是符合ES模块规范的mock返回,即可正常解构导入:

jest.mock('child_process', () => ({
  __esModule: true,
  execSync: jest.fn(),
}));

import { execSync } from 'child_process';
execSync.mockImplementation(() => {
  return something;
});

使用spyOn实现相同mock的方案

完全可以用spyOn实现,且更适合多测试用例需要不同mock实现的场景,支持随时恢复原方法实现,避免用例间的mock污染,具体用法如下:

// 不需要提前调用jest.mock完整mock整个模块
import * as childProcess from 'child_process';

describe('测试分组', () => {
  afterEach(() => {
    // 每个测试用例结束后恢复所有spy的原实现
    jest.restoreAllMocks();
  });

  it('测试用例1', () => {
    jest.spyOn(childProcess, 'execSync').mockImplementation(() => '用例1的返回值');
    // 执行你的测试逻辑
  });

  it('测试用例2', () => {
    jest.spyOn(childProcess, 'execSync').mockImplementation(() => '用例2的返回值');
    // 执行你的测试逻辑
  });
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 03:45:07