在测试自定义 Hooks 时,模拟(Mock)外部依赖是确保测试准确性和独立性的关键。外部依赖可能包括 API 调用、浏览器 API、第三方库等。以下是如何使用 Jest 等工具进行 Mock 的具体方法和示例:
一、Mock 基本概念
- 目的:隔离被测试的 Hook,排除外部依赖的干扰
- 核心工具:Jest 提供的
jest.mock()
、jest.spyOn()
等方法 - 原则:只关注 Hook 的逻辑,而非外部依赖的实际实现
二、常见外部依赖的 Mock 方法
1. Mock 浏览器 API(如 localStorage
、fetch
)
示例:Mock localStorage
示例:Mock fetch
API
2. Mock 定时器(setTimeout
、setInterval
)
对于依赖定时器的 Hook(如倒计时、轮询),使用 Jest 的定时器 Mock:
3. Mock 第三方库
如果自定义 Hook 依赖第三方库(如 lodash
、date-fns
),可以直接 Mock 整个库:
4. Mock 上下文(Context)依赖
当 Hook 依赖 React Context 时,可以通过模拟上下文提供者来注入测试数据:
三、Mock 工具与技巧
jest.mock()
:完全替换模块,适用于第三方库或工具函数
// 自动模拟整个模块
jest.mock('./api');
jest.spyOn()
:部分替换对象的方法,保留其他功能
// 只Mock localStorage.getItem,保留其他方法
const getItemSpy = jest.spyOn(Storage.prototype, 'getItem').mockReturnValue('mocked-value');
mockResolvedValue
/mockRejectedValue
:模拟异步函数的成功/失败返回
// 模拟API成功响应
fetch.mockResolvedValue({ ok: true, json: () => ({ data: 'test' }) });
// 模拟API失败响应
fetch.mockRejectedValue(new Error('Network error'));
- 清理 Mock:避免测试用例之间的相互影响
afterEach(() => {
jest.clearAllMocks(); // 清除调用记录
// 或 jest.resetAllMocks(); // 清除调用记录并重置实现
});
四、最佳实践
- 只 Mock 必要的依赖:避免过度 Mock 导致测试与实际环境脱节
- 验证 Mock 调用:不仅要测试 Hook 的输出,还要验证它是否正确调用了外部依赖
- 模拟边缘情况:如网络错误、超时、空返回等异常场景
- 保持 Mock 简单:Mock 实现应尽可能简单,只返回测试所需的数据
- 区分单元测试与集成测试:单元测试中应 Mock 所有外部依赖,集成测试则可使用真实依赖
通过合理使用 Mock 技术,可以确保自定义 Hooks 的测试聚焦于自身逻辑,不受外部依赖的波动影响,从而提高测试的稳定性和可靠性。