mcpField
T
test-writing

test-writing

github.com/wilbeibi测试与质量278 次安装5 天前更新
代码仓库

关于 test-writing

面向开发者和编码 Agent 的测试技能,帮助选择可靠且成本较低的验证边界。重点是围绕行为编写测试、保持环境可控、让失败原因明确,并完成项目要求的检查。

主要功能

  1. 01根据复杂度所在位置选择测试范围
  2. 02优先采用可控且低成本的测试环境
  3. 03测试行为而非实现结构
  4. 04条件允许时使用真实本地依赖
  5. 05让失败原因集中且可观察

适用场景

  1. 01为涉及领域逻辑的改动选择测试方式
  2. 02在本地验证数据库或文件系统行为
  3. 03围绕服务边界规划集成测试
  4. 04检查脆弱或误导性的断言

安装

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

$npx skills add https://github.com/wilbeibi/wilbeibi-skills --skill test-writing

安装后在 Claude Code 中输入/test-writing确认已加载。

附带文件REFERENCE.md

详细介绍

test-writing

通过最宽泛且仍保持环境隔离、易于搭建的边界来测试行为。

根据改动选择适当的验证方式,并完成项目要求的检查。 不要仅仅为了遵循偏好的测试风格而扩大生产范围。

需要改正的习惯

  • 根据刚写的代码编写测试。 阅读实现并断言其行为,会把其中的缺陷也固化下来。应从需求推导预期值,并手动计算。如果不运行代码就无法说出预期结果,那你还没有充分理解相关行为,暂时无法对其进行测试。
  • 把实际输出复制到预期结果中。 运行测试,看到它失败,然后把实际值粘贴进去,得到的是记录,而不是测试。把容差不断放宽直到测试通过,也是一样。
  • 照搬代码结构。 每个源文件对应一个测试文件、每个公有方法对应一个测试,这是一套以代码为单位的测试集。应以行为为单位进行测试;一个行为由多少个类实现并不重要。
  • 默认使用模拟。 如果真实的本地依赖既便宜又能确保结果一致,就优先使用它。在外部边界使用伪对象或模拟对象,前提是它能提供可靠的信号;仅仅因为存在模拟对象,并不足以成为重新设计的理由。
  • 修测试,而不是修代码。 在证实之前,失败的测试只是假设代码有问题。绝不要为了让测试变绿而弱化断言、添加模拟对象或跳过测试。在同一个提交中修改测试及其覆盖的代码时,必须说明两者为何都有问题。
  • 修改环境来让测试变绿。 手动插入一行数据、切换标志、重启服务或清空队列,都是部署环境层面的弱化断言——测试通过了,问题却没解决,而且共享状态也因此发生了偏移,影响所有其他人。
  • 在共享环境中盲目试错调试。 共享环境中的失败运行本来就很难判断原因:可能是你的改动、别人的改动、过期数据,也可能是环境损坏。先在本地通过环境隔离的测试复现;如果做不到,就如实说明,而不是猜测。
  • 盲目接受快照。 不查看差异就运行更新模式,会把 expect-test 循环变成自动批准循环。未审核的快照更新应视为未经测试的改动。
  • 堆砌测试。 廉价的测试会变成近乎重复的测试,既会一起失败,又会掩盖真正的故障。覆盖率百分比和测试数量都不是目标。
  • 掩盖失败。 避免使用重试或异常处理来让损坏的行为显示为通过。对于异步行为,可以设置有界等待和超时,但失败必须保持清晰可见。
  • 测试框架本身。 断言 ORM 能保存数据或标准库能排序,实际上是在测试别人的代码。

在 Agent 循环中,测试集不是安全网,而是正在被优化的验收标准。循环论证式的测试集不仅会漏掉缺陷,还会把工作引向错误的方向。

路由

首先要弄清复杂性实际存在于哪里,因为这决定了整套测试的形态:

  • 在进程内部 — 算法、领域规则、解析器。在领域层深入测试;边界测试只能证明接线正确。
  • 在边界处 — 服务、胶水代码、编排。契约就是产品,因此要从边缘开始,使用贴近实际的固定数据,并将实现细节测试限制在少数真正复杂且隔离的部分。

然后:

  1. 简单的胶水代码/getter?跳过 — 不可能失败的测试只会给故障信号带来噪声。
  2. 纯逻辑、依赖很少?通过公共 API 测试。优先选择属性测试或穷举测试,而不是手工挑选示例。
  3. 编排、真实 I/O、控制器/数据库/文件系统行为?做集成测试 — 单独测试模块或服务,让它自己的依赖保持真实,在边缘伪造协作者。
  4. 既复杂又依赖繁多?提取领域逻辑并测试它;保留一个精简的编排器用于集成测试。
  5. 部署、接线、真实第三方行为,或负载下的基础设施?只有这些情况需要部署环境。优先采用临时环境(每个 PR 一个环境、compose 文件),而不是共享的预发布环境。

逐步扩大边界,直到准备工作变得昂贵或测试不再是纯隔离的,然后停止。I/O 不是判断标准 — 回环 HTTP 和进程内 SQLite 的成本很低,而共享远程数据库则不然。真正带来成本的是准备时间、资源占用,以及任何你无法控制的东西。

规则

  • 常规测试应独立于共享外部服务。验证真实外部契约时,可明确使用集成测试或端到端检查;并将环境故障单独报告。
  • 故障必须能定位缺陷。只说明“系统中有问题”的失败结果几乎毫无价值,因为下一步只能猜。
  • 一个测试 = 一个领域专家能够识别的场景。按行为命名,而不是按方法命名。
  • 优先使用基于输出的测试,其次是基于状态的测试;仅在对兼容性敏感的外部调用中使用通信模拟。
  • 对非托管依赖优先使用伪造对象;条件允许时,使用真实的本地数据库/文件系统。让边界与被测行为相匹配。
  • 对依赖时间的行为,优先注入时钟或使用项目既有的假计时器机制。等待异步工作完成,或通过有时限的公共信号观察其完成情况。
  • 准备、执行、断言。执行阶段只做一个操作。断言范围要窄,以便故障只指向一个原因。
  • 将准备工作限定在需要它的测试中。类级共享固定数据会拖累每次单独的测试运行,而这正是你调试时要进行的运行。
  • 对缓存命中或回退使用等行为,优先利用现有的公共可观测性。仅当所需契约需要时才添加检测,不要只为断言某个实现分支而添加。

危险信号

  • 预期值是根据实际输出反推出来的,而不是依据需求确定的。
  • 测试复制了生产逻辑,而不是将答案硬编码。
  • 测试会因重构而失败,因为它检查了内部实现、私有方法、调用顺序或类布局。
  • 测试必须依赖多个服务运行,或依赖共享环境处于健康状态才能通过。
  • 数据库/文件系统行为被模拟掉。
  • 使用无上限的休眠/重试,或会抑制故障的条件判断。
  • 测试与它覆盖的代码在同一个提交中被修改,却没有任何解释。

质量标准

判断测试是否合格,要看它能否提供可信的验证信号:行为出错时会失败,重构后仍能通过,并且失败时能明确指出一个显而易见的原因。抗重构能力最为重要 — 它决定了整套测试通过究竟意味着什么。锁定错误结构的测试比没有测试更糟,因为人们会相信它。

关于测试规模、金字塔/蜂窝模型的选择、check() 接缝、可观测性节点、期望测试、属性测试与模糊测试、谦逊对象重构以及数据库模式,请参阅 REFERENCE.md。

评论

支持 Markdown