如何在Node.js的Jest测试中正确mock fs.readdir并解决ENOENT报错
问题修复方案
错误原因
你的写法不生效存在两个核心问题:
- 业务代码在模块初始化阶段就已经执行了
const readdir = util.promisify(fs.readdir)赋值,测试用例中再监听util.promisify时,该赋值逻辑早已执行完成,监听逻辑无法拦截到已经生成的readdir方法。 - 直接对原始
readdir变量调用mockReturnValueOnce无效,因为它本身不是Jest生成的Mock函数。
可行解决方案
方案一:直接Mock fs模块的readdir方法(最稳妥)
不管上层用什么工具包装回调方法,直接拦截底层fs.readdir即可:
const fs = require('fs'); // 替换为你的业务模块路径 const Files = require('./your-module-path'); // 全局mock整个fs模块 jest.mock('fs'); it('test read', async () => { // 模拟回调风格的readdir返回成功结果 fs.readdir.mockImplementation((dirPath, callback) => { // 第一个参数为错误对象,传null表示调用成功,第二个参数为返回的文件列表 callback(null, ['test1.js', 'test2.js']); }); const result = await Files.test(); expect(result).toEqual('success'); // 可选:验证调用参数是否符合预期 expect(fs.readdir).toHaveBeenCalledWith('directory path', expect.any(Function)); });
方案二:提前Mock util.promisify返回值
需要保证Mock逻辑执行在业务模块导入之前:
const util = require('util'); // 第一步:先监听util.promisify方法 const promisifySpy = jest.spyOn(util, 'promisify'); // 定义mock的readdir异步方法 const mockReaddir = jest.fn().mockResolvedValue(['test1.js', 'test2.js']); // 让promisify调用后直接返回我们的mock方法 promisifySpy.mockReturnValue(mockReaddir); // 第二步:再导入业务模块,此时业务模块中拿到的readdir就是我们的mock方法 const Files = require('./your-module-path'); it('test read', async () => { const result = await Files.test(); expect(result).toEqual('success'); expect(mockReaddir).toHaveBeenCalledWith('directory path'); });
你遇到的ENOENT报错本质是Mock逻辑未生效,代码依然调用了原生readdir读取不存在的路径,以上两种方案都可以规避对原生方法的调用,解决该报错。
内容的提问来源于stack exchange,提问作者Anjana
相关产品推荐
相关产品推荐

