JavaScript单元测试要真正“单元”,关键在于隔离外部依赖:用mock替换真实模块或函数,控制时间与异步行为,显式传入依赖而非硬编码调用,避免操作DOM和全局状态,确保测试独立可靠。

JavaScript 单元测试要真正“单元”,关键就是把被测函数和外部环境完全切开。不是不调用,而是不让它真实发生——比如不发真实请求、不读写 localStorage、不依赖 Date.now() 的当前时间、也不执行 setTimeout 回调。隔离不是为了绕过问题,而是为了让测试只反映你写的逻辑是否正确。
用 Mock 替换真实依赖
Jest 和 Vitest 都提供原生 mock 能力,核心是拦截调用并返回可控结果:
- 用 jest.mock('axios') 或 vi.mock('node-fetch') 拦截整个模块,再通过 mockResolvedValue 返回假响应
- 对单个函数 mock:用 jest.fn() 创建模拟函数,传入被测模块作为依赖(需配合依赖注入)
- 避免直接在测试里改写 global.fetch = jest.fn(),这种全局污染易导致测试间干扰
控制时间与异步行为
真实时间、定时器会让测试不可靠或变慢:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用 jest.useFakeTimers() 冻结时间,再用 jest.runAllTimers() 或 vi.advanceTimersByTime(1000) 主动推进
- 不要写 await new Promise(resolve => setTimeout(resolve, 100)),这既慢又不可控
- 测试中涉及 Date 时,可用 jest.setSystemTime(new Date('2023-01-01')) 统一基准时间
避免隐式依赖,显式传入可替换项
如果函数内部自己调用 localStorage.getItem 或 fetch,就很难 mock。更可测的写法是把依赖作为参数传入:
立即学习“Java免费学习笔记(深入)”;
- 把 apiClient 或 storage 当作参数,而不是在函数里硬编码调用
- 这样测试时就能传入一个 mock 对象,比如 { getItem: jest.fn().mockReturnValue('token') }
- 这种手动依赖注入不靠框架,简单直接,也符合 JavaScript 的轻量特性
不碰 DOM 和全局状态
单元测试不渲染组件、不查 document 元素、不依赖 window 属性:
- React 组件单元测试推荐用 @testing-library/react,但它本质仍是隔离渲染,只断言输出结构,不操作真实 DOM
- 避免在测试前设置 localStorage.setItem 后不清除,否则可能影响后续测试
- 每个测试用例应独立运行,用 beforeEach(() => { jest.clearAllMocks() }) 重置 mock 状态

















