
本文详解如何在 Vitest 中为每个测试用例独立、可重置地模拟 JSON 文件导入,解决静态导入导致的 mock 失效问题,确保 validateData() 等依赖 JSON 数据的函数能被精准、隔离地测试。
本文详解如何在 vitest 中为每个测试用例独立、可重置地模拟 json 文件导入,解决静态导入导致的 mock 失效问题,确保 `validatedata()` 等依赖 json 数据的函数能被精准、隔离地测试。
在 Vitest 中直接使用 vi.mock() 对 JSON 文件(如 data/data.json)进行全局模拟,往往无法实现“每测试一 mock”的预期效果——因为模块在测试文件顶层已被静态解析并缓存,后续对 mock 返回值的修改(如 mockReturnValueOnce)不会影响已导入的模块实例。
根本原因在于:ESM 的静态导入(import { validateData } from './validator.js')在模块加载时即完成,且 JSON 模块被一次性解析并缓存。即使你通过 vi.mock() 重定义了模块导出,若 validateData 及其依赖的 JSON 已在 describe 外部导入,则 mock 并未在该导入链中生效。
✅ 正确解法:结合 vi.doMock() + 动态 import() + vi.resetModules()
-
vi.doMock()是 延迟生效 的 mock,仅对后续的import()调用起作用; -
await import('./validator.js')在每个test内动态导入,触发全新模块加载流程,此时doMock配置生效; -
vi.resetModules()在afterEach中调用,清空 Node.js 模块缓存(require.cache和 Vitest 内部模块注册表),确保下个测试从干净状态重新导入。
以下是推荐的完整实践模板:
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
const obj1 = {
id: 1,
name: 'obj1'
};
describe('validateData', () => {
afterEach(() => {
vi.resetModules(); // ✅ 关键:重置模块缓存,避免跨测试污染
});
test('with valid data', async () => {
vi.doMock('data/data.json', () => ({
default: { obj1 } // ✅ 每次 test 定义专属 mock 数据
}));
const { validateData } = await import('./validator.js'); // ✅ 动态导入,触发新 mock
expect(validateData()).toStrictEqual([]);
});
test('with missing field', async () => {
vi.doMock('data/data.json', () => ({
default: { obj1: { ...obj1, name: undefined } }
}));
const { validateData } = await import('./validator.js');
expect(validateData()).toStrictEqual(['Missing name for obj1']);
});
test('with empty object', async () => {
vi.doMock('data/data.json', () => ({ default: {} }));
const { validateData } = await import('./validator.js');
expect(validateData()).toStrictEqual(['No objects found']);
});
});
⚠️ 注意事项:
-
勿混用
vi.mock()与vi.doMock():vi.mock()是 hoisted 的预编译期 mock,适用于顶层稳定依赖;而vi.doMock()是运行时按需 mock,专为动态场景设计; -
路径必须精确匹配:
vi.doMock('data/data.json')中的路径需与import语句中实际使用的路径完全一致(包括扩展名); -
JSON 导入默认为命名空间对象:Vitest 默认将
.json视为 ESM 模块,导出{ default: … },因此doMock返回对象必须包含default属性; - 若项目启用
jsonModule: true(如 Vite 5+),也可直接导出裸对象,但为兼容性建议始终显式返回{ default }。
通过该模式,每个测试都拥有完全隔离的模块上下文,JSON 数据可自由定制,validateData() 的行为验证真正做到了输入驱动、边界清晰、可重复验证——这才是单元测试可靠性的基石。










