Jest测试中使用performance.now()进行计时的准确性有多高?
关于Jest性能测试的可行性解答
1. 现有测试方案无法满足2σ下20%置信度要求
你当前的代码仅统计平均耗时,没有涉及离散度计算,完全无法验证95%的执行耗时落在均值±20%的区间内:
- 2σ置信度的核心是基于样本标准差做判断,你需要先存储每一次
doThing()的独立耗时,而非直接在reduce中累加均值 - 最终验证逻辑需要满足
2 * 样本标准差 ≤ 0.2 * 样本均值,才符合你提出的性能要求 - 需要保证足够的样本量,建议至少执行100次以上的重复测试,才能让标准差统计结果具备可信度
你可以参考如下改进后的测试代码:
test('doThing 耗时满足2σ±20%要求', () => { const numberOfReps = 200; const durations = []; for(let i = 0; i < numberOfReps; i++) { // 若需统计首执行耗时,可在此处重置模块/业务缓存,避免缓存影响结果 const m0 = performance.now(); doThing(); const m1 = performance.now(); durations.push(m1 - m0); } // 计算均值 const avg = durations.reduce((sum, cur) => sum + cur, 0) / durations.length; // 计算标准差 const variance = durations.reduce((sum, cur) => sum + Math.pow(cur - avg, 2), 0) / durations.length; const stdDev = Math.sqrt(variance); // 验证2σ是否在均值20%范围内 expect(2 * stdDev).toBeLessThanOrEqual(0.2 * avg); })
2. 你对Jest插入额外执行逻辑的担忧具备合理性
默认配置下Jest确实可能在你统计的时间区间内插入额外执行逻辑,常见的影响场景包括:
- 开启代码覆盖率统计时,Babel会向所有业务代码插入覆盖率打点逻辑,显著拉长执行耗时,同时引入额外的离散度
- 配置了自定义Jest全局钩子、mock插件或第三方测试扩展时,可能在测试执行过程中触发额外的同步/异步逻辑
- Jest默认的多线程并行执行模式下,CPU资源抢占会导致单函数执行耗时的统计出现不可控的波动
3. 优化统计准确性的建议
- 执行性能测试时关闭代码覆盖率,禁用所有非必要的Jest插件与自定义生命周期钩子
- 给性能测试用例单独配置
runInBand参数,避免和其他测试用例并行执行抢占CPU资源 - 如果需要统计首执行耗时,每次执行
doThing()前重置对应模块的缓存,避免JIT编译、业务缓存对结果的影响;如果不需要统计首执行,可提前预热3~5次再正式统计,排除编译阶段的干扰 - 对准确性要求极高的场景,可将性能统计逻辑独立为Node.js原生脚本执行,彻底规避Jest框架的额外开销,统计结果的可信度会更高
内容的提问来源于stack exchange,提问作者lmonninger
相关产品推荐
相关产品推荐

