mcpField
V
vitest-best-practices

vitest-best-practices

github.com/gohypergiant测试与质量2554 次安装2 周前更新
代码仓库

关于 vitest-best-practices

面向开发者的 Vitest 测试实践指南,涵盖测试清晰度、隔离性与性能,并按需提供分主题参考规则。

主要功能

  1. 01测试组织与命名指导
  2. 02Arrange–Act–Assert 结构
  3. 03使用 it.each() 编写参数化测试
  4. 04断言与测试替身
  5. 05异步、性能和快照测试指导

适用场景

  1. 01设计清晰的 Vitest 测试套件
  2. 02避免 Mock 泄漏和顺序依赖故障
  3. 03为外部依赖选择测试替身

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/gohypergiant/agent-skills --skill vitest-best-practices

安装后在 Claude Code 中输入/vitest-best-practices确认已加载。

详细介绍

Vitest 最佳实践

编写可维护、高效 vitest 测试的全面模式。专注于测试组织、清晰度和性能方面的专家级指导。

编写 Vitest 测试时绝不要做的事

  • 绝不要跳过全局 mock 清理配置 - 手动清理看似安全,却会造成"隔空作用"式失败:测试文件 A 中的 mock 泄漏到 3 个文件之后运行的测试文件 B 中,导致仅在特定测试运行顺序下才出现的非确定性失败。这些海森堡 bug 会在 CI 调试中浪费数小时。在 vitest.config.ts 中一次性配置 clearMocks: true、resetMocks: true、restoreMocks: true,即可消除这整类依赖顺序的失败。
  • 绝不要将 describe 块嵌套超过 2 层 - 深层嵌套会造成认知负担和过度缩进。把上下文放进测试名称中:it('should add item to empty cart') 对比 describe('when cart is empty', () => describe('addItem', ...))。
  • 绝不要 mock 你自己的纯函数 - Mock 内部代码会让测试变得脆弱且价值降低。只 mock 外部依赖(API、数据库、第三方库)。优先选择 fake > stub > spy > mock。
  • 绝不要使用 toBeTruthy() 或 toBeDefined() 这类宽松断言 - 这些断言会为你从未预期的多个不同值通过:toBeTruthy() 对 1、"false"、[] 和 {} 都通过——它们在语义上完全不同。当重构将 getUser() 的返回值从 {id: 1} 改为 1 时,你的测试仍然通过,但生产代码却会崩溃。宽松断言制造出在生产环境中蒸发殆尽的虚假信心。toBeTypeOf() 不是宽松断言。
  • 绝不要测试实现细节而非行为 - 验证"函数 X 被调用了 3 次"的测试会造成虚假失败:你通过记忆化优化代码,使其只调用 X 一次,所有测试都失败,而用户体验却完全相同(甚至更快)。这些测试实际上是在惩罚性能改进和重构。测试用户能观察到的内容(给定输入得到的输出),而不是你的代码内部如何实现。
  • 绝不要在测试之间共享可变状态 - 依赖执行顺序或前一个测试状态的测试会造就脆弱、不可靠的测试套件。每个测试都必须完全独立,拥有全新的 setup。
  • 绝不要在测试文件中使用 any 或跳过类型检查 - 当实现签名发生变化时,带 as any 的测试会静默通过,同时却在用错误的参数调用函数。你会发布 TypeScript 本可以捕获的破损代码。测试是可执行的文档:user as any 什么也没传达,而 createTestUser(Partial<User>) 则准确展示了此测试用例中哪些属性才是重要的。

编写测试前,先问

在实现测试之前,应用这些专家思维模式:

测试隔离与 setup
  • 清理逻辑应该放在哪里? 分层思考:配置消除整类错误(vitest.config.ts 中的 mock 清理),setup 文件处理项目级关注点(自定义匹配器、全局 mock),beforeEach 处理测试特定的状态。每个测试各自做 mock 清理,就像每个函数各自做 null 检查——能工作,却没抓住重点。把关注点推到合适的最高层。
  • 此测试是否依赖之前的测试或共享状态? 测试套件是平行宇宙——每个测试无论第一个运行、最后一个运行还是单独运行,都应表现一致。状态依赖会造就"量子测试",通过与否取决于执行顺序。如果一个测试需要另一个测试的数据,它们实际上是被人为拆成两个的一个测试。
测试什么
  • 我在测试行为还是实现? 测试用户实际体验到的内容(输入 → 输出),而不是代码如何实现(调用了哪些函数)。实现测试会在安全重构时失效。
  • 我能使用的最简单的依赖是什么? 真实实现 > fake > stub > spy > mock。在这个层级中每下降一步都会增加脆弱性。只有在使用真实代码不切实际时(外部 API、慢操作)才使用 mock。
测试清晰度
  • 别人能在 5 秒内理解这个测试吗? 遵循 AAA 模式(Arrange、Act、Assert),并划清边界。如果 setup 很复杂,就提取为名称具有描述性的辅助函数。
  • 同一行为是否存在多种变体? 使用 it.each() 编写参数化测试,而不是复制测试结构。每个概念只做一个断言可让测试保持聚焦。
性能与维护
  • 这个测试在 6 个月后仍然有价值吗? 避免测试框架内部机制或琐碎操作。专注于业务逻辑、边界情况和真正能防止 bug 的错误处理。
  • 这个测试是否快到能在每次保存时运行? 避免在测试中进行昂贵的操作。对数据库使用 fake,对延迟使用 mock 计时器,对外部调用使用 stub。测试应在毫秒内完成。

本 Skill 涵盖的内容

关于 vitest 测试模式的专家指导:

  1. 组织 - 文件放置、命名、describe 块结构
  2. AAA 模式 - Arrange、Act、Assert,实现即时清晰
  3. 参数化测试 - 使用 it.each() 减少重复
  4. 错误处理 - 测试异常、边界情况、故障注入
  5. 断言 - 使用严格断言捕获意外值
  6. 测试替身 - fake、stub、mock、spy 的层级以及各自的使用场景
  7. 异步测试 - Promise、async/await、计时器、并发测试
  8. 性能 - 通过高效 setup 和全局配置实现快速测试
  9. Vitest 特性 - 覆盖率、监听模式、setup 文件、配置发现
  10. 快照测试 - 快照何时有助于可维护性、何时有害

如何使用

本 Skill 采用 渐进式披露 结构,以尽量减少上下文占用:

1. 从概览开始(AGENTS.md)

阅读 AGENTS.md,获取所有规则的精简概览,其中包含一行摘要以及发现现有测试配置的工作流。

2. 检查现有测试配置

在编写测试之前:

  • 首先检查 vitest.config.ts 中的全局 mock 清理设置(clearMocks、resetMocks、restoreMocks)
  • 然后搜索 setup 文件(test/setup.ts、vitest.setup.ts 等)并分析其配置
  • 参见 AGENTS.md 中的工作流
3. 按需加载特定规则

使用以下明确的触发条件来判断何时加载每个参考文件:

强制加载(加载整个文件):

看到以下模式时加载:

除非特别需要,否则不要加载:

4. 应用模式

每个参考文件包含:

  • ❌ 展示反模式的错误示例
  • ✅ 展示最佳实现的正确示例
  • 对该模式为何重要的解释

快速示例

有关完整的 before/after 示例,请参阅 quick-start.md,了解此技能如何将不清晰的测试转变为清晰、可维护的测试。

评论

支持 Markdown