AIHero
    25 / 25为真正的工程师打造的 AI 技能 · 8 分钟阅读

    /tdd 技能

    红-绿-重构循环的规则。

    Matt Pocock
    Matt Pocock

    安装此技能

    npx skills@latest add mattpocock/skills --skill=tdd

    然后输入 /tdd 来调用它。

    本页内容

    它的作用

    tdd 以测试先行构建功能或修复 bug:先一个失败的测试,然后只写刚好能通过它的代码,然后是下一个行为。它带有让这个循环产出值得保留测试的标准——什么是好测试、测试放在哪、mock 是干什么的,以及三个悄悄毁掉测试套件的反模式。

    它不会在你未预先同意的接缝处写测试。在任何测试存在之前,它点名打算测试的公共边界,并停下来等你的确认,因为测试精力是有限的,这里正是你把它花在关键路径而不是每个边界情况上的地方。另一件要知道的事是 tdd 是一个 reference,而不是驱动者。它持有循环的规则,而其他角色(你,或 implement)运行 会话 应用它们。

    何时使用

    输入 /tdd,或这个 agent 任务合适时自动调用它——测试先行地构建功能或修复 bug,或当你说「红-绿-重构」时。

    当有具体行为要构建、有输入和可观察的输出、并且你想要经得起重构的测试时使用它。

    你的情境去哪里
    一个具有明确输入和输出的行为——业务逻辑、请求/响应契约、转换、校验tdd
    行为还没被钉死to-spec,它还会在任何代码写出之前就约定测试接缝
    问题其实是接口的形状,而不是测试codebase-design
    你有一个 spec or tickets 并想让整个构建替你完成implement,它驱动 tdd 每个任务
    配置、接线、胶水、类型注解、直白 CRUD 委托这里没有合适的——见下面所述的开放缺口

    最后一行是真实的漏洞,不是风格偏好。技能决定 where 接缝放在哪;其中没有任何东西决定 whether 一个改动是否值得走这个循环。在一个没有独立真相来源可断言的改动上运行它,你会得到一个复述实现的测试——正是该技能自己警告过的同义反复反模式,只是从另一个方向到达。它是 issue #746 并且它是开放的。在它关闭之前,那个判断由你或你的 CLAUDE.md的。

    前置条件

    codebase-design 需要被安装。 tdd 曾携带自己的深模块和接口设计笔记;在 v1.0 中它们被删除,让位于共享技能,而 tdd 现在依赖它提供接口设计词汇。没有别的——该技能是 无状态 并且不写自己的文件。

    循环,以及它运行的接缝

    三个词撑起这个技能。

    红-绿。 写失败的测试,然后只写刚好能通过它的代码。不要预想后面的测试。没有重构阶段:它在 2026 年 6 月被移除,因为智能体实际上从不执行它,也因为审查和实现分开成独立会话效果更好。重构属于 code-review.

    垂直切片。 一个接缝、一个测试、一个最小实现,然后重复——第一个循环是 曳光弹 端到端证明一条路径。相反的是横向切片:先全部测试,再全部代码。批量测试验证的是 imagined 行为时,它们检查的是事物的形状而不是用户做了什么,而且它们会在你理解实现之前就把你绑定到一种测试结构上。

    预先约定的接缝。 接缝是你在不深入内部的情况下观察行为的公共边界。规则是绝对的:未经确认的接缝处不写测试。在完整链条中,接缝在更早的阶段就被约定,即在 to-spec ——“/tdd 被告知只在预先约定的测试接缝处工作, /code-review 检查只使用了约定的测试接缝。」单独调用时, tdd 直接问你。

    它写来预防的三个反模式:

    反模式征兆
    实现耦合重命名内部函数时测试破裂,尽管行为没有改变。被 mock 的内部协作者、被断言的调用次数、用来验证的数据库查询——而不是接口。
    同义反复期望值按代码的计算方式计算,所以测试在构造上必然通过。期望值必须来自别处——已知正确的字面量、算过的例子、规格说明。
    横向切片一批测试在实现之前就落地了。

    Mock 只用于系统边界——外部 API、时间、随机性,有时是文件系统或数据库。不是你自己的模块。

    常见问题

    它为什么不重构?描述说「红-绿-重构」。

    因为重构步骤被移除了,而描述没有。移除是刻意的:智能体实际上从不做它,而且把实现和审查分开在不同会话效果更好。结果是否还算书上的 TDD,远不如循环是否产出更好的代码重要。触发短语与正文之间的不匹配已作为 issue #589 并且仍然开放,所以「红-绿-重构」这个短语仍然能触发该技能。你得到的是红 → 绿,以及 code-review.

    它让我选测试接缝,我完全不知道该选哪个。

    这是该技能被报告最多的摩擦(issue #607)。提示词只按名称列出候选接缝,没有说明每个接缝能抓住什么或漏掉什么,所以你是在标签之间做选择。目前还没有发布修复。实用的变通方案是在回答之前先问智能体权衡关系——组件级接缝会漏掉哪些集成级接缝能抓住的东西,它又慢多少。这也是链条要在 to-spec,在那里你能看到整个功能,而不是一个提示词。

    它先写了实现,尽管技能说先红。

    确实会发生。一位用户按下了 model 并得到了异常诚实的回答:「我知道技能说'一次一个测试,看它因正确的原因失败'——我读过。我只是默认回到了自己的习惯。」技能就是为与这种情况共存而写的。没有任何指令能让智能体 100% 遵守,而更用力地强制只会限制智能体的创造力,收益却很小——即使没有被严格遵守,这个循环也值得运行,因为整体结果仍然更好。如果对某个特定切片严格遵从很重要,那就盯住运行,而不是指望技能来强制执行。

    它应该先写浏览器测试还是端到端测试?

    通常不会,而技能不会阻止它。一位用户报告智能体先写 Playwright 测试,然后烧掉一个长循环重跑它,并得出 test 为一个尚不存在的功能而损坏。在你的 CLAUDE.md。浏览器测试慢到红-绿反馈循环不再划算;在你的仓库的 CLAUDE.md 它们是在行为工作之后才写下的。

    是否 /tdd replace /implement,或课程的 /do-work?

    不。 /tdd 记录方法论; /implement 是一个非常简单的工作→反馈→提交循环,是 /do-work。课程的唯一 /do-work 步骤现在被拆在 /implement, /tdd and /code-review。如果你在问对某个任务该运行哪一个,答案几乎总是 /implement.

    深模块和接口设计指南去哪了?

    进入 codebase-design 在 v1.0 中,经过泛化让多个技能共享一套词汇。 refactoring.md 同时离开;重构现在 code-review的职责,而那个技能带有 Fowler 坏味道基线。

    它知道我其他的任务吗?

    不。对着一个任务运行时,它会乐此不疲地提议属于兄弟任务的工作,因为它看不到 issue 图的其余部分(issue #129)。Matt 的立场是这不是 tdd的职责。把规格说明与任务一起传递会有帮助;从一开始就把任务切成合适大小更有帮助。

    做到以下就算成功

    • 在任何测试文件存在之前,它停下来点名打算测试的接缝,然后等待。
    • 一个测试出现、变红、得到刚好够通过的代码,然后下一个测试才出现——而不是一批测试后面跟着一批代码。
    • 测试名读起来是能力(「用户可以用有效购物车结账」),而不是内部实现(「checkout 调用 paymentService.process」)。
    • 断言中的期望值是你能追溯到规格说明的字面量,而不是按代码的计算方式重算出来的值。
    • 重命名内部函数不会破坏测试套件中的任何东西。
    • Mock 只出现在外部边界——支付 API、时钟——绝不会出现在你自己的模块周围。

    在流程中的位置

    tdd 是主链构建步骤内部的引擎,而不是独立的一步:

    grill-with-docs → to-spec → to-tickets → implement → code-review

    to-spec 预先约定测试接缝, implement drives tdd 每个任务,而且 code-review 事后检查只使用了约定的接缝——并负责重构 tdd 不再如此了。它的另一个邻居是 codebase-design,接缝与深模块词汇的共同来源 tdd 说话。只要有具体行为要构建且没有完整规格说明在手,你也可以单独使用它。当你不确定哪个技能适合你的情境时, ask-matt 为你指路。

    技能操作

    安装技能

    Live Skills.sh install count
    npx skills@latest add mattpocock/skills

    安装整套技能,然后在智能体中输入 /tdd 来调用它。

    用以下命令更新: npx skills updateSkills.sh