核心是隔离执行环境和控制模块加载边界,通过测试沙箱(如jest的jest.isolatemodules())为每个测试创建独立模块上下文,确保require/import从干净状态开始,全局对象可临时重写并自动还原,避免跨测试污染。

单元测试中处理全局变量污染,核心是隔离执行环境和控制模块加载边界。不靠“不污染”,而靠“污染了也不影响其他测试”。
用测试沙箱(Sandbox)隔绝副作用
像 Nodeunit 的 sandbox() 工具,或 Jest 中的 jest.isolateModules(),都能为每个测试用例创建独立的模块加载上下文:
- 每次
require或import都从干净状态开始,不会复用上一个测试缓存的模块实例 - 全局变量(如
window、global、process)可被临时重写或清空,测试结束后自动还原 - 适合测试依赖全局状态的旧代码,比如操作
document.cookie或修改Date.now的函数
在测试前主动清理和模拟全局对象
很多污染来自测试中意外修改了全局对象。可在 beforeEach 或 afterEach 中统一干预:
- 重置被篡改的全局属性:
delete global.MyLegacyUtil或global.Date = originalDate - 用
jest.mock('node:fs', () => ({ readFileSync: jest.fn() }))模拟原生模块,避免真实 I/O 或环境副作用 - 对浏览器环境,可临时替换
window.location或localStorage为内存对象,防止跨测试残留
避免在模块顶层写有副作用的代码
污染常源于模块加载时就执行逻辑(如自动注册、初始化、挂载到 window)。重构建议:
- 把初始化动作移到函数内,由调用方显式触发,而非模块
require时自动运行 - 使用工厂函数替代单例:导出
createService()而非直接导出已初始化的service - ESM 中利用
import.meta.url判断是否在测试环境,跳过非必要全局挂载
用模块打包器或测试框架的隔离能力
现代工具链本身提供防护层:
- Jest 默认启用
resetModules: true(可配),确保每个test独立require缓存 - Vitest 支持
vi.resetAllMocks()+vi.restoreAllMocks(),一键还原所有 mock 状态 - Rollup/Vite 测试环境下可通过插件拦截
import,注入纯净版本的依赖
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











