Vitest retry 配置详解:失败重试次数、延迟与条件控制(config/retry)

发布时间:2026/9/14 4:33:37

Vitest retry 配置详解:失败重试次数、延迟与条件控制(config/retry) Vitest retry 配置详解失败重试次数、延迟与条件控制config/retry【免费下载链接】vitestNext generation testing framework powered by Vite.项目地址: https://gitcode.com/GitHub_Trending/vi/vitestVitest 的retry配置用于在测试失败时按指定次数自动重试是处理网络抖动、偶发超时、资源竞态等flaky tests不稳定测试的最直接手段。本文以 docs/config/retry.md 为主线完整讲解retry的三种配置形态——纯数字、对象count/delay/condition以及测试文件内的逐测试覆盖并结合仓库源码剖析其底层实现帮助你精准控制何时重试、重试几次、每次间隔多久。配置总览retry的完整类型定义为Type:number | { count?: number, delay?: number, condition?: RegExp }Default:0即默认不重试CLI:--retry times、--retry.count times、--retry.delay ms、--retry.condition pattern从源码看这一类型定义在 packages/vitest/src/runtime/runner/types.ts 中的SerializableRetryexport type SerializableRetry number | { count?: number // 失败后重试次数default 0 delay?: number // 两次重试之间的延迟毫秒数default 0 condition?: RegExp // 与错误消息匹配的 RegExpdefault undefined所有错误都重试 }而 packages/vitest/src/node/types/config.ts 中对应的test.retry字段注释明确指出函数形式的 condition 不能在配置文件中使用因为配置文件会被序列化后传给 worker 线程函数无法被序列化。基础用法数字形式最简单的做法是给retry传入一个数字表示失败后重试的次数// vitest.config.ts export default defineConfig({ test: { retry: 3, }, })设置retry: 3意味着首次执行 失败后最多重试 3 次即单个测试最多执行 4 次只要其中任何一次通过该测试即被判定为通过。从实现上看这一语义对应 packages/vitest/src/runtime/runner/run.ts 中的重试循环const retry getRetryCount(test.retry) for (let retryCount 0; retryCount retry; retryCount) {getRetryCount同文件 L47-L55负责把number或{ count?: number }统一归一化为次数retryCount retry的循环条件保证了首次 retry 次的总执行次数。当测试通过时循环会直接breakL741-L743后续重试不再执行。CLI 用法retry同样支持从命令行覆盖配置# 简单的重试次数 vitest --retry 3 # 使用点号dot notation表达高级选项 vitest --retry.count 3 --retry.delay 500 --retry.condition ECONNREFUSED|timeout这些 CLI 选项定义在 packages/vitest/src/node/cli/cli-config.ts。值得注意的是condition子命令的transform逻辑condition: { description: Regex pattern to match error messages that should trigger a retry. Only errors matching this pattern will cause a retry (default: retry on all errors), argument: pattern, transform: (value) { if (typeof value string) { return new RegExp(value, i) // 自动附加 i 标志不区分大小写 } return value }, },也就是说通过 CLI 传入的 pattern 字符串会被自动编译为不区分大小写的正则表达式例如上面的ECONNREFUSED|timeout等价于/ECONNREFUSED|timeout/i。高级选项对象形式Vitest 4.1.0当需要精细控制重试行为时可以传入对象// vitest.config.ts export default defineConfig({ test: { retry: { count: 3, // 重试次数 delay: 1000, // 重试之间的延迟毫秒 condition: /ECONNREFUSED|timeout/i, // 仅当错误消息匹配该正则时才重试 }, }, })count测试失败后重试的次数默认0。export default defineConfig({ test: { retry: { count: 2, }, }, })它等价于数字形式的retry: 2只是为后续扩展delay、condition预留了位置。实现上由getRetryCount归一化function getRetryCount(retry: number | { count?: number } | undefined): number { if (retry undefined) { return 0 } if (typeof retry number) { return retry } return retry.count ?? 0 }delay两次重试尝试之间的延迟毫秒默认0。官方文档强调它特别适合与限流rate-limitedAPI 交互或需要时间恢复的场景——例如第三方接口瞬时 429、数据库连接池暂时耗尽、上游服务正在滚动发布等。export default defineConfig({ test: { retry: { count: 3, delay: 500, // 每次重试前等待 500ms }, }, })重试延迟的实现位于 packages/vitest/src/runtime/runner/run.tsconst delay getRetryDelay(test.retry) if (delay 0) { await new Promise(resolve setTimeout(resolve, delay)) }getRetryDelayL57-L65同样兼容数字与对象两种形式。仓库中的 test/unit/test/retry-delay.test.ts 对这个行为有直接的验证一个断言计数必须等于 3 的测试配置retry: { count: 2, delay: 100 }首次执行必然失败、经两次 100ms 延迟后重试成功随后另一个测试校验总耗时 200ms确认 delay 真实生效it(retry with delay, { retry: { count: 2, delay: 100, }, }, () { if (delayCount 0) { delayStart Date.now() } delayCount 1 expect(delayCount).toBe(3) }) it(verify delay was applied, () { const duration Date.now() - delayStart expect(delayCount).toBe(3) // With 2 retries and 100ms delay each, should take at least 200ms expect(duration).toBeGreaterThanOrEqual(200) })conditioncondition决定是否根据错误内容触发重试。它有两种形态RegExp对错误消息error.message进行匹配函数接收错误对象并返回布尔值。警告当condition是函数时必须在测试文件中直接定义不能写在配置文件里——配置文件会被序列化传给 worker 线程函数无法跨线程序列化。正则 condition配置文件内export default defineConfig({ test: { retry: { count: 2, condition: /ECONNREFUSED|ETIMEDOUT/i, // 仅在连接/超时类错误时重试 }, }, })函数 condition测试文件内import { describe, test } from vitest describe(tests with advanced retry condition, () { test(with function condition, { retry: { count: 2, condition: error error.message.includes(Network) } }, () { // test code }) })函数 condition 的底层判断逻辑packages/vitest/src/runtime/runner/run.tsfunction passesRetryCondition(test: Test, errors: TestError[] | undefined): boolean { const condition getRetryCondition(test.retry) const error errors?.at(-1) // 取最近一次失败的错误 if (error null) { return false } if (!condition) { return true // 未配置 condition所有错误都重试 } if (condition instanceof RegExp) { return condition.test(error.message || ) // 正则匹配错误消息 } else if (typeof condition function) { return condition(error) // 函数自定义判定 } return false }三个关键语义值得注意condition缺省时所有错误都会触发重试return true正则匹配的是最近一次失败的错误消息且基于error.message函数形式接收的是完整的TestError对象而非仅字符串因此可以基于error.name如TimeoutError、error.stack等字段做更精细的判定。SerializableRetry类型注释packages/vitest/src/runtime/runner/types.ts也印证了这一点RegExp 测试错误消息函数则接收TestError返回布尔值且只能用于测试文件。为什么配置文件中不能用函数源码 packages/vitest/src/node/config/resolveConfig.ts 给出了答案if (resolved.retry typeof resolved.retry object typeof resolved.retry.condition function) { logger.warn( c.yellow(Warning: retry.condition function cannot be used inside a config file. Use a RegExp pattern instead, or define the function in your test file.), ) resolved.retry { ...resolved.retry, condition: undefined, // 函数条件被静默丢弃 } }Vitest 检测到配置中的函数 condition 时会发出警告并将其置为undefined退化为所有错误都重试。此外test.tags中定义的自定义标签若带函数 condition则直接抛出TypeError同文件 L307-L309。原因正如类型定义所述配置需要序列化后跨线程传递。测试文件内覆盖按测试 / 按套件重试retry同样可以作为测试选项在单个test()或describe()级别覆盖全局配置——这在某几个测试特别不稳定但不想全局开启重试时非常实用import { describe, test } from vitest describe(flaky tests, { retry: { count: 2, delay: 100, }, }, () { test(network request, () { // test code }) }) test(another test, { retry: { count: 3, condition: error error.message.includes(timeout), }, }, () { // test code })这里的函数 condition 位于测试文件内部不经过配置序列化因此可以放心使用。测试文件中的选项会合并到测试任务的retry字段上运行时统一由getRetryCount/getRetryDelay/getRetryCondition读取。与 repeats 的区别配置中还有一个容易混淆的相邻选项repeats见 packages/vitest/src/node/types/config.tsretry只在失败时重试而repeats是无论成败都重复执行指定次数。二者的循环在 packages/vitest/src/runtime/runner/run.ts 中嵌套实现const repeats test.repeats ?? 0 for (let repeatCount 0; repeatCount repeats; repeatCount) { const retry getRetryCount(test.retry) for (let retryCount 0; retryCount retry; retryCount) {外层是 repeats无条件下重复内层才是 retry失败后按条件重试二者可以组合使用。重试状态与报告重试过程中Vitest 会维护每个测试的retryCount并触发test-retried任务事件packages/vitest/src/runtime/runner/run.tstest.result.state run test.result.retryCount (test.result.retryCount ?? 0) 1 const delay getRetryDelay(test.retry) if (delay 0) { await new Promise(resolve setTimeout(resolve, delay)) } // update retry info updateTask(test-retried, test, runner)这意味着你可以在自定义 reporter 中监听test-retried事件来感知重试行为同时retryCount也会进入测试结果供报告器展示第几次尝试后通过。相关任务状态字段定义在 packages/vitest/src/node/reporters/reported-tasks.ts其中retry字段以SerializableRetry类型随任务一起上报。结合 Hook 与 Fixture 的语义需要留意的是重试并不仅仅是重新执行测试函数。从 packages/vitest/src/runtime/runner/run.ts 的重试循环可以看到每次重试都会重新执行beforeEach/afterEach钩子、aroundEachfixtures 及其清理逻辑并触发onBeforeTryTask/onAfterTryTask/onAfterRetryTask等 runner 回调参数中携带当前的retry: retryCount与repeats: repeatCount。因此写在beforeEach中的状态初始化每次重试都会重新执行避免上一次失败残留污染下一次尝试每次重试拥有独立的测试上下文test.context与 fixture 生命周期如果失败发生在beforeAll/afterAll这类套件级钩子中重试不会覆盖该错误——套件级钩子的失败仍会使整个套件失败。实战建议与限制基于文档与源码以下是实践中比较可靠的使用策略先定位再重试重试是治标手段不应掩盖真正的确定性 bug。建议先排查根因仅对已知偶发网络超时、限流、时序竞争的用例开启。用 condition 收窄范围默认所有错误都重试可能掩盖真实故障。配合condition: /ECONNREFUSED|ETIMEDOUT/i之类正则只对特定错误重试其余错误立即暴露。合理设置 delay对限流接口建议delay 500对本地资源竞争可保持delay: 0立即重试避免拖慢整个测试套件。仓库的 test/unit/test/retry-delay.test.ts 同时验证了delay: 100与delay: 0两种路径。优先在测试文件内做局部覆盖全局retry会影响所有测试文件包括本应快速失败的断言按测试/套件覆盖更加精准。不要在配置文件中写函数 condition会被警告并静默降级为重试所有错误。需要函数判定时把它放进测试文件的测试选项中。重试次数与报告联动retry: 3意味着单测最多执行 4 次会放大执行时间与外部调用次数注意对 CI 总时长的影响。小结retry是 Vitest 处理不稳定测试的核心配置项数字形式快速开启对象形式通过count/delay/condition实现次数 间隔 错误筛选的精细控制测试文件内覆盖则提供了按用例定制的灵活性。其底层由 packages/vitest/src/runtime/runner/run.ts 中的重试循环与条件判定统一驱动类型定义集中在 packages/vitest/src/runtime/runner/types.ts相关行为均有 test/unit/test/retry-condition.test.ts 与 test/unit/test/retry-delay.test.ts 等单元测试直接验证。合理组合这三要素就能在不掩盖真实缺陷的前提下显著提升测试套件在真实网络环境下的稳定性。【免费下载链接】vitestNext generation testing framework powered by Vite.项目地址: https://gitcode.com/GitHub_Trending/vi/vitest创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/14 4:33:37

被芯代工厂技术资质审计指南:供应链合规验证框架与实操避坑经验

直接跑被芯工厂做合作前审计,这件事听起来不像技术活,但真正做过的人都知道,它比看代码、审系统复杂得多。生产线上的每一道工序、每一卷填充棉、每一台绗缝机的针距,背后都是一套可以验证的工程逻辑。我这几年带队走访过不少家纺…

2026/9/14 4:33:37

Windows 64位下PostgreSQL客户端SSDT Hook绕过原理与实现

简介:本资源是一份面向Windows内核安全研究者与高级逆向工程师的64位SSDT Hook实战教程,聚焦于绕过Process Guard(PG)保护机制后实现系统服务表劫持的核心技术。内容涵盖二次挑战式绕过PG的原理分析、SSDT修改流程及配套驱动开发实…

2026/9/14 5:18:39

网络安全就业“离谱”背后:岗位、技能与求职全解析

不知道你们最近刷招聘软件是什么感受,我今年光是后台私信和社群里面聊到的网络安全就业问题,就比前两三年加起来还多。“离谱”这个词,已经不只是夸张,而是很多人共同的情绪:岗位数量看着不算少,简历投出去…

2026/9/14 5:18:39

JSP医疗系统如何用链式哈希实现防篡改数据模型

简介:一套基于JSPJava技术的医疗数据管理系统源码,面向Java Web开发者与健康医疗领域的课程设计、毕业设计人群。系统采用B/S模式,整合区块链数据模型用于医疗数据的安全管理,可在Tomcat7.0、Myeclipse8.5环境下搭配MySQL数据库运…

2026/9/14 5:18:39

16台DGX Spark本地部署Kimi K3:企业级大模型推理基建实践

1. 这不是玩具,是实打实的本地大模型推理基建:16台英伟达小盒子跑Kimi K3到底在干啥? “花50万,16台英伟达小盒子组集群,本地跑Kimi K3”——这标题一出来,圈内人第一反应不是“哇好有钱”,而是…

2026/9/14 5:13:39

文章分享的技术实现与工程实践

我理解您的要求,但需要坦诚说明:当前输入内容中,项目标题仅为“分享文章”四个字,且无任何实质性描述、关键词、摘要或上下文信息。该标题过于宽泛,缺乏领域指向(是技术类文章?自媒体运营&#…

2026/9/14 2:17:50

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/14 0:03:22

KCF目标跟踪算法与OTB工程实现:毕业设计实战解析

简介:这是一份基于KCF核相关滤波算法、融合尺度池与抗遮挡处理的目标检测跟踪MATLAB完整源码,主要面向计算机相关专业准备毕业设计、课程设计或期末大作业的学生,也适合需要项目实战练习的初学者。源码在OTB数据集上完成验证,能够…

2026/9/14 0:03:22

语音情感识别实战:Keras实现LSTM、CNN、SVM与MLP多模型对比

简介:面向语音情感识别入门与进阶开发者,这份基于Keras的项目源码完整实现了LSTM、CNN、SVM、MLP四种模型,兼容Python3.8与Keras/TensorFlow2环境。压缩包内含49个文件,大小约70.31MB,主体包括Python脚本、yaml/json配…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/12 14:32:17

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/13 11:18:28

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码