JavaScript单元测试隔离全局依赖的核心是切断对真实全局环境的直接调用,改用可控mock或替换版本:①模块级mock(如jest.mock/vi.stubGlobal);②封装为可注入依赖;③代理或沙箱环境(如jsdom/vm);④避免delete全局属性,优先覆盖并配合beforeEach重置。

在 JavaScript 单元测试中隔离复杂的全局对象依赖,核心思路是**切断测试代码对真实全局环境的直接调用**,改用可控的模拟(mock)或替换(stub)版本。关键不在于“完全禁止访问全局”,而在于让每次测试拥有独立、可预测、无副作用的运行上下文。
用模块级 mock 替换全局对象(推荐)
现代测试框架(如 Jest、Vitest)支持在模块作用域内精准 mock 全局变量。例如,要隔离 window.fetch 或 Date:
- Jest 中可在测试文件顶部用
jest.mock('node:fs')模拟内置模块;对全局构造器(如XMLHttpRequest),可用global.XMLHttpRequest = class { ... }覆盖 - Vitest 中用
vi.stubGlobal('fetch', mockFetch)或vi.mock('./utils', () => ({ getTime: vi.fn() }))控制导出行为 - 注意:mock 应在
beforeEach中重置,避免测试间污染;用vi.restoreAllMocks()清理
封装全局访问为可注入依赖
把对 localStorage、navigator.geolocation 等的直接调用,提取成函数或类,并通过参数/构造器注入:
- 原代码:
localStorage.setItem('token', value)→ 测试时无法替换 - 重构后:
function saveToken(storage, key, value) { storage.setItem(key, value); },测试时传入内存对象{ setItem: jest.fn() } - 更进一步:用依赖注入容器(如 InversifyJS)或工厂函数统一管理,使测试能提供轻量替代实现
使用代理或沙箱环境做运行时隔离
对难以静态替换的场景(如第三方 SDK 修改了 window 属性),可临时创建干净上下文:
立即学习“Java免费学习笔记(深入)”;
- 用
jsdom在 Node 环境中模拟浏览器 DOM,每个测试用独立JSDOM实例,天然隔离window和document - 对纯逻辑模块,用
vm.createContext(Node)运行代码,手动挂载最小化全局对象,不继承真实globalThis - 慎用
delete globalThis.xxx—— 可能破坏其他测试,优先选覆盖而非删除
避免常见陷阱
有些做法看似隔离,实则埋下隐患:
- 不要在
afterEach中恢复全局对象 —— 应在beforeEach初始化,确保每个测试从干净状态开始 - 警惕“隐式依赖”:比如函数内部调用
console.warn影响日志断言,需用vi.spyOn(console, 'warn').mockImplementation(() => {})拦截 - 时间相关测试必须控制
Date.now()或setTimeout,否则出现 flaky test;Jest 提供jest.useFakeTimers(),Vitest 有vi.useFakeTimers()


















