使用Jest模拟Node.js的fs模块失效,求正确模拟方法
问题:Jest模拟fs模块失效,触发真实文件读取错误
我正在使用TypeScript、Jest、ts-node,尝试模拟fs模块的部分函数来测试自定义模块。
tsconfig.json核心配置如下:
... "target": "ESNext", "module": "NodeNext", "moduleResolution": "nodenext", ...
测试文件mocking.test.ts代码如下:
import * as fs from 'fs'; import { jest } from '@jest/globals' jest.mock("fs", () => ({ readFileSync: jest.fn().mockReturnValue("test"), })); describe('mock test', () => { it('should read file content', () => { expect(fs.readFileSync("abcd.test", "utf8")).toBe("test"); // 运行时触发错误:ENOENT: no such file or directory, open 'abcd.test' }); });
运行测试时触发了真实fs模块的文件不存在错误,模拟未生效,请问原因是什么?该如何正确模拟?
原因分析
你的tsconfig配置了module: NodeNext和moduleResolution: nodenext,这会让项目采用ES模块解析规则。而Jest默认的jest.mock提升机制在ES模块环境下不生效——ES模块的import是静态解析并优先执行的,导致你导入的是真实的fs模块,而非Jest生成的模拟版本。
正确解决方法
方法1:调整jest.mock执行顺序(推荐)
在ES模块环境下,必须让jest.mock在所有import之前执行,才能覆盖真实模块的导入。修改测试代码如下:
import { jest } from '@jest/globals'; // 先调用jest.mock,再导入fs jest.mock('fs', () => ({ readFileSync: jest.fn().mockReturnValue('test'), })); // 必须在jest.mock之后导入fs import * as fs from 'fs'; describe('mock test', () => { it('should read file content', () => { expect(fs.readFileSync('abcd.test', 'utf8')).toBe('test'); }); });
方法2:切换到CommonJS模块规则
如果项目不需要严格使用ES模块,可以修改tsconfig配置,切换到CommonJS解析规则:
"module": "CommonJS", "moduleResolution": "node"
此时Jest的传统jest.mock提升机制会正常工作,原测试代码无需大幅修改。
方法3:使用jest.spyOn模拟单个方法
如果只需要模拟fs的特定方法,而非替换整个模块,jest.spyOn在ES模块环境下更稳定:
import * as fs from 'fs'; import { jest } from '@jest/globals'; describe('mock test', () => { it('should read file content', () => { // 模拟readFileSync方法 const mockReadFileSync = jest.spyOn(fs, 'readFileSync').mockReturnValue('test'); expect(fs.readFileSync('abcd.test', 'utf8')).toBe('test'); // 测试完成后恢复原方法 mockReadFileSync.mockRestore(); }); });
内容的提问来源于stack exchange,提问作者Victor
相关产品推荐
相关产品推荐

