JavaScript单元测试中Mock动态导入需用vi.mock/jest.mock拦截import()返回的Promise,路径须字面量严格匹配且mock前置;可模拟成功、失败、延迟状态;重点验证组件加载时机、结果处理及错误降级行为。

在 JavaScript 单元测试中 Mock 动态导入(import()),核心是拦截 import() 表达式返回的 Promise,使其不真实加载模块,而是返回可控的模拟值。这在测试国际化语言包、按需加载组件、插件系统等场景非常关键。
用 Jest 或 Vitest 拦截动态导入
Jest 和 Vitest 都支持通过 vi.mock / jest.mock 拦截 ESM 动态导入,但必须满足两个前提:
- 被 mock 的路径需与
import()中的字符串字面量完全一致(包括扩展名); - mock 必须在
import()实际执行前完成(通常放在测试文件顶部或beforeEach中)。
// ✅ 正确:mock './locales/zh-CN.json',路径和扩展名严格匹配
vi.mock('./locales/zh-CN.json', () => ({
default: { greeting: '你好' }
}));
test('loads zh-CN and renders greeting', async () => {
const mod = await import('./locales/zh-CN.json');
expect(mod.default.greeting).toBe('你好');
});⚠️ 注意:不能 mock
'./locales/' + lang + '.json'这类拼接路径——测试框架无法静态分析,mock 会失效。
模拟成功、失败、延迟等典型场景
动态导入本质是 Promise,因此可 mock 成不同状态:
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
立即学习“Java免费学习笔记(深入)”;
-
成功加载:返回带
default的对象(符合 ES 模块默认导出规范) - 加载失败:抛出错误,验证降级逻辑(如 fallback 语言)
-
延迟加载:返回
new Promise(resolve => setTimeout(() => resolve({...}), 100)),配合await waitFor(...)测试 loading 状态
// 模拟失败
vi.mock('./locales/ja-JP.json', () => {
throw new Error('Failed to load ja-JP');
});
// 模拟延迟
vi.mock('./locales/en-US.json', async () => {
await vi.waitFor(() => vi.advanceTimersByTime(200));
return { default: { hello: 'Hello' } };
});测试组件中动态导入的真实行为
不要只测 import() 本身,要测它如何影响组件渲染:
// UserProfile.tsx
async function loadLocale(lang) {
const mod = await import(`./locales/${lang}.json`);
return mod.default;
}
export default function UserProfile({ lang }) {
const [t, setT] = useState(() => () => '');
useEffect(() => {
loadLocale(lang).then(setT);
}, [lang]);
return <div>{t('user_profile')}</div>;
}对应测试:
test('renders translated text after dynamic import', async () => {
vi.mock('./locales/zh-CN.json', () => ({ default: { user_profile: '用户资料' } }));
render(<UserProfile lang="zh-CN" />);
expect(screen.queryByText(/用户资料/)).not.toBeInTheDocument();
await waitFor(() => expect(screen.getByText(/用户资料/)).toBeInTheDocument());
});避免常见陷阱
- ❌ 不要
import locale from './locales/zh-CN.json'后断言内容——那是静态导入,没测“动态”行为; - ❌ 不要在
vi.mock里写require('./locales/zh-CN.json')——ESM 环境下会报错; - ❌ 不要 mock 全局
import函数——它不可写,且违反模块系统约束; - ✅ 推荐统一用
vi.mock(Vitest)或jest.mock(Jest),配合vi.unmock清理副作用。
动态导入的测试重点不在“能不能 import”,而在于“是否按预期时机加载、是否正确处理结果、是否优雅应对失败”。mock 只是手段,验证行为协同才是目的。

















