Jest.doMock无法条件化模拟JSON导入问题排查与解决
问题:Jest无法在单个测试用例中条件化模拟JSON导入
我来帮你拆解这个问题——你遇到的核心问题是模块加载时机导致的mock失效,下面详细分析原因和解决方案:
问题回顾
你的待测试代码逻辑是导入JSON数据,异步返回数据或抛出错误:
import data from '../data/mock.json'; // 异步函数 export const something = async () => { try { if (!data) { throw 'error is here!'; } return data; } catch (error) { return error; } };
测试代码尝试用jest.doMock为不同用例设置不同的JSON模拟数据,但发现mock并未生效;全局mock可以工作,但无法区分用例。
为什么你的mock没生效?
关键点在于:你在测试文件顶部静态导入了something函数,这会在Jest执行任何测试代码之前就加载handler.js模块,而handler.js又会立刻加载原始的mock.json。
后续你在测试用例里设置的jest.doMock和重新import mock.json,都不会影响已经加载完成的something函数——它已经绑定了最初的data引用,所以mock根本没生效。
解决方案:动态导入目标函数
要实现不同测试用例的条件化mock,你需要延迟导入something函数,确保它在你设置好mock之后才被加载。具体步骤如下:
- 移除测试文件顶部的静态
import { something } from './handler'; - 在每个测试用例内部,先设置
jest.doMock,再通过import()动态导入something - 保留
beforeEach里的jest.resetModules(),确保每个测试用例的模块环境相互隔离
修改后的测试代码
describe('handler: something', () => { beforeEach(() => { jest.resetModules(); }); describe('on something', () => { it('should return data', async () => { const data = [ { id: 1, price: '1', }, { id: 2, price: '2', }, ]; // 1. 先设置mock jest.doMock('../data/mock.json', () => { return { __esModule: true, default: data, }; }); // 2. 动态导入目标函数 const { something } = await import('./handler'); // 3. 执行断言 await expect(something()).resolves.toEqual(data); }); it('should return error', async () => { jest.doMock('../data/mock.json', () => ({ __esModule: true, default: undefined, })); // 动态导入 const { something } = await import('./handler'); await expect(something()).resolves.toBe('error is here!'); }); }); });
补充说明
jest.resetModules()会在每个测试用例前重置模块缓存,确保每次动态导入都是全新的模块实例,不会受到之前测试用例的mock影响- 因为JSON文件在ES模块中是作为默认导出的,所以mock时必须设置
__esModule: true和default属性,这部分你之前的写法是正确的 - 待测试代码不需要做任何修改,保持原来的逻辑即可
这样调整后,每个测试用例都会先设置好对应的mock数据,再加载handler模块,此时something函数引用的就是你mock后的data,就能实现条件化的模拟了。
内容的提问来源于stack exchange,提问作者byCoder
相关产品推荐
相关产品推荐

