
本文介绍在 jest 测试中,针对 __mocks__ 目录下导出的变量(如 token),如何在特定测试用例中安全、局部地覆盖其值,避免影响其他测试,同时绕过 jest 模块缓存与只读导出限制。
本文介绍在 jest 测试中,针对 __mocks__ 目录下导出的变量(如 token),如何在特定测试用例中安全、局部地覆盖其值,避免影响其他测试,同时绕过 jest 模块缓存与只读导出限制。
在 Jest 中,__mocks__ 文件夹用于提供模块级模拟实现,其导出内容默认被所有测试共享且不可变(尤其当使用 export const 或 export let 时,Jest 会将其视为静态绑定)。因此,直接通过 jest.spyOn() 修改导出变量、或尝试 jest.unmock() 切换回真实模块,往往无效——因为 __mocks__/example.ts 并非被自动 mock 的目标模块(它本身就是一个 mock 实现),而 Jest 对 ESM 导出的绑定是运行时只读的,无法动态重赋值。
✅ 正确解法:利用 JavaScript 作用域屏蔽(shadowing),在单个测试用例内声明同名局部变量,而非试图修改导入的绑定。
假设你的 mock 文件如下(推荐使用 const 提升可预测性):
// __mocks__/example.ts export const token = 'exampleString';
在测试文件中,你无需修改导入方式,而是直接在 it() 块内定义同名变量:
// __tests__/foo.spec.ts
import { token } from '../__mocks__/example.ts'; // 导入仅用于类型/占位,实际不使用
import foo from '../foo.ts';
describe('foo', () => {
it('uses default token', () => {
const actual = foo.doSomething(token); // 使用 __mocks__ 中的默认值
expect(actual).toContain('exampleString');
});
it('uses null token for edge case', () => {
const token = null; // ✅ 局部变量屏蔽(shadow)了导入的 token
const actual = foo.doSomethingElse(token);
expect(actual).toBeNull();
});
});
⚠️ 关键注意事项:
- 不要尝试 jest.mock('../__mocks__/example.ts'):该路径不是被自动 mock 的原始模块(如 ../example.ts),手动 mock 它会导致冗余或冲突;
- 避免 export let + jest.resetModules():即使重置模块,ESM 的 export let 在 Jest 中仍受模块缓存与绑定机制限制,不可靠;
- 确保测试函数接收 token 作为参数:这是实现局部覆盖的前提;若被测代码直接从 __mocks__/example.ts 导入并使用 token,则必须重构为依赖注入(例如将 token 作为函数参数或通过配置对象传入),否则无法隔离覆盖;
- 类型提示建议:可在测试中显式标注类型以增强可读性:const token: string | null = null;
? 进阶提示:若需更灵活控制多个 mock 状态(如 token、user、config 等),可封装为工厂函数或使用 jest.isolateModules() 配合动态导入,但对单变量覆盖场景,作用域屏蔽是最轻量、最可靠的方式。










