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
相关产品推荐
相关产品推荐

