Jest中如何resolve被mock回调函数返回的Promise
问题根源
执行jest.mock('fs')后,Jest会自动对fs模块做全量mock:模块下所有方法都会被替换为默认返回undefined的空函数,不会执行任何原有逻辑。
你的代码里fs.readFile被mock后,完全不会调用你传入的回调函数,导致loadData返回的Promise一直处于pending状态,测试等不到resolve/reject结果就会触发超时。
另外你写的loadData本身存在逻辑漏洞:当fs.readFile返回err触发reject(err)后,没有加return终止后续逻辑执行,会继续往下走data解析流程,容易抛出意料之外的错误。
修复方案
1. 修正业务代码逻辑漏洞
先给loadData里两处reject之后加上return,阻断后续逻辑执行:
const fs = require('fs'); const path = require('path'); function loadData(fileName){ let promise = new Promise((resolve, reject) => { fs.readFile(path.join(__dirname, `/${fileName}`), (err, data) => { if (err) { console.error(err) reject(err); return; } data = data.toString(); try{ data = JSON.parse(data); } catch(err){ console.error(err) reject(new Error('Error while parsing json')) return; } resolve(data); }) }) return promise; } module.exports = { loadData };
2. 给mock的fs.readFile自定义实现
自动生成的空mock不会触发回调,你需要手动编写mock实现,在readFile被调用时主动执行传入的回调函数,传入模拟的错误或文件数据,驱动Promise走完状态流转:
jest.mock('fs'); const fs = require('fs'); const DI = require('./../data/data_interface'); describe('data loading functionality',() => { test('load data opens file system',async () => { expect.assertions(1); const testFileName = 'expenses.json'; // 模拟文件内容 const mockFileContent = JSON.stringify({ expenses: [] }); // 自定义readFile mock逻辑 fs.readFile.mockImplementation((filePath, callback) => { // 第一个参数传null代表无读取错误,第二个参数传模拟的文件Buffer数据 callback(null, Buffer.from(mockFileContent)); }); await DI.loadData(testFileName); // 验证readFile被调用了1次 expect(fs.readFile.mock.calls.length).toBe(1); }) })
其他测试场景的mock写法
你可以通过调整mockImplementation里传给回调的参数,覆盖不同的异常分支:
- 测试文件读取失败场景:给回调传入错误对象作为第一个参数,比如
callback(new Error('file not found'), null),此时Promise会走读文件失败的reject逻辑 - 测试JSON解析失败场景:给回调传入非JSON格式的Buffer作为第二个参数,比如
callback(null, Buffer.from('invalid json content')),此时会触发JSON解析错误的reject逻辑
内容的提问来源于stack exchange,提问作者vipul ahuja
相关产品推荐
相关产品推荐

