使用 jest 的 fake timers(jest.usefaketimers())控制时间流,通过 jest.advancetimersbytime() 推进时间并断言 settimeout 调用时机和 fetch 请求次数,可精准验证请求重试间隔,需注意定时器清理、异步时机及避免封装 settimeout。

在 JavaScript 单元测试中验证请求重试的间隔时间,核心是**控制时间流 + 检查定时器调用时机**,而不是等待真实时间过去。直接用 jest.useFakeTimers() 配合 jest.advanceTimersByTime() 或 jest.runOnlyPendingTimers() 是最可靠的方式。
用 fake timers 模拟时间推进
确保测试环境使用 Jest 的假定时器,并在测试前后正确初始化和清理:
- 在
beforeEach中调用jest.useFakeTimers() - 在
afterEach中调用jest.useRealTimers()防止污染其他测试 - 被测函数内部必须使用标准的
setTimeout(不能被封装成黑盒、未 mock 的工具函数)
断言重试是否在预期时间点触发
假设你有一个 fetchWithRetry(url, { maxRetries: 2, delay: 1000 }) 函数,首次失败后应在 1000ms 后重试:
- 用
mockImplementationOnce让第一次请求抛错,第二次成功 - 调用函数后,立即检查
setTimeout是否被调用(expect(setTimeout).toHaveBeenCalledTimes(1)) - 用
jest.getTimerCount()确认当前存在待执行定时器 - 调用
jest.advanceTimersByTime(1000)推进时间,再断言第二次请求是否发出(如expect(fetch).toHaveBeenCalledTimes(2))
验证连续重试的时间间隔(如指数退避)
若重试策略是 1000ms → 2000ms → 4000ms,可分步推进并断言:
- 首次失败后,
advanceTimersByTime(1000)→ 断言第 2 次请求发生 - 再次失败,
advanceTimersByTime(2000)→ 断言第 3 次请求发生 - 注意:每次
advanceTimersByTime后,Jest 会自动执行该时间段内所有到期定时器
避免常见陷阱
几个容易出错的地方:
-
没清空定时器:测试结束前不调用
jest.clearAllTimers()可能导致后续测试异常 -
异步断言时机错误:不要在
advanceTimersByTime前就await请求结果;fake timers 下 Promise 不自动 resolve,需靠时间推进触发回调 -
封装了 setTimeout:如果重试逻辑里调用的是
delay(1000).then(...)且delay内部用了new Promise(r => setTimeout(r, ...)),只要没重写 Promise 构造函数,fake timers 仍生效
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











