如何编写测试验证API限流功能正常生效?
限流测试实现方案
核心思路
通过nock拦截所有目标API请求,统计每个请求的实际触发时间,验证任意1秒窗口内的请求数量不超过6次即可。不需要修改原有业务逻辑,只需要在测试层做请求埋点统计。
具体实现步骤
- 初始化时间戳数组,用于存储每个请求实际触发的时间
- 配置nock拦截目标API的所有请求,每次命中拦截时将当前时间戳推入数组,返回正常mock响应
- 一次性发起远高于限流阈值的请求(比如12次,覆盖至少2个限流窗口)
- 等待所有请求执行完成后,滑动统计所有1秒时间窗口内的请求数,验证最大值不超过6
示例代码(基于Jest测试框架)
const { yourApiCallFunc } = require('./你的API调用模块路径') const nock = require('nock') test('API调用限流规则验证:每秒请求数不超过6次', async () => { const TARGET_API_HOST = 'https://你调用的外部API域名' const requestTimestamps = [] const TEST_REQUEST_COUNT = 12 // 触发2倍限流阈值的请求,验证跨窗口限流效果 // 配置nock拦截所有目标请求 nock(TARGET_API_HOST) .persist() // 允许重复拦截同规则请求,不加的话默认仅拦截1次 .get('/你的接口路径') // 替换为实际请求的方法和路径,post请求就用.post .reply(200, () => { // 拦截到请求时记录当前时间戳 requestTimestamps.push(Date.now()) return { code: 0, data: {} } }) // 一次性触发所有API请求 const allRequestPromises = Array(TEST_REQUEST_COUNT).fill(0).map(() => yourApiCallFunc()) // 等待所有请求执行完毕 await Promise.all(allRequestPromises) // 先验证所有请求都正常触发,避免逻辑遗漏导致的假阳性 expect(requestTimestamps.length).toBe(TEST_REQUEST_COUNT) // 滑动统计所有1秒窗口内的最大请求数 let maxRequestInOneSecond = 0 for (let i = 0; i < requestTimestamps.length; i++) { const currentWindowStart = requestTimestamps[i] const currentWindowCount = requestTimestamps.filter( timestamp => timestamp >= currentWindowStart && timestamp < currentWindowStart + 1000 ).length maxRequestInOneSecond = Math.max(maxRequestInOneSecond, currentWindowCount) } // 核心断言:每秒请求数不超过6 expect(maxRequestInOneSecond).toBeLessThanOrEqual(6) // 可选额外断言:验证总耗时符合限流逻辑,避免限流完全失效的场景 const totalCostTime = requestTimestamps.at(-1) - requestTimestamps[0] expect(totalCostTime).toBeGreaterThanOrEqual(Math.floor(TEST_REQUEST_COUNT / 6) * 1000) })
注意事项
- 如果测试框架开启了时间模拟(fake timer),需要临时关闭该配置,或者同步推进limiter内部的时间计数,否则时间冻结会导致限流逻辑不生效
- 如果你的API调用函数内部自带重试逻辑,测试前需要关闭重试,或者调整统计逻辑排除重试请求的重复计数
- 如果你的限流规则是固定窗口而非滑动窗口,也可以用固定窗口统计逻辑替换上面的滑动窗口统计,验证结果更精准
内容的提问来源于stack exchange,提问作者Daniel Cutter
相关产品推荐
相关产品推荐

