mcpField
T
tdd

tdd

github.com/helderberto测试与质量1948 次安装4 天前更新
代码仓库

关于 tdd

面向开发者和编码 Agent 的 TDD 技能,强调通过公共接口验证行为,并以增量式红绿循环推进。它要求先确认测试边界和仓库使用的测试命令,再开始实现。

主要功能

  1. 01通过公共接口测试行为
  2. 02逐步进行红绿循环
  3. 03发现仓库专用测试命令
  4. 04确认测试边界与计划
  5. 05测试通过后再重构

适用场景

  1. 01围绕可观察行为规划测试
  2. 02逐项实现系统行为
  3. 03避免测试依赖内部实现

安装

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

$npx skills add https://github.com/helderberto/agent-skills --skill tdd

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
mocking.md
tests.md
ui-tests.md

详细介绍

测试驱动开发

理念

核心原则:测试应通过公共接口验证行为,而不是实现细节。代码可以彻底改变;测试不应改变。

好的测试采用集成测试的方式:通过公共 API 执行真实的代码路径。它们描述系统_做什么_,而不是_怎么做_。好的测试读起来就像一份规范——“用户可以使用有效购物车结账”能明确告诉你系统具备什么能力。这类测试经得起重构,因为它们不关心内部结构。

糟糕的测试与实现紧密耦合。它们会模拟内部协作者、测试私有方法,或通过外部手段验证(例如直接查询数据库,而不是使用接口)。警示信号是:重构时测试失败,但行为并未改变。如果重命名一个内部函数就导致测试失败,那么这些测试验证的是实现,而不是行为。

示例见 tests.md,模拟指南见 mocking.md,用户流程端到端测试见 ui-tests.md。

反模式:水平切片

不要先写完所有测试,再写完所有实现。 这就是“水平切片”——把 RED 阶段当作“写完所有测试”,把 GREEN 阶段当作“写完所有代码”。

这会产生糟糕的测试:

  • 批量编写的测试验证的是_想象中的_行为,而非_实际的_行为
  • 最终测试的是事物的_形态_(数据结构、函数签名),而非面向用户的行为
  • 测试会对真正的变化不敏感——行为出问题时测试通过,行为正常时测试反而失败
  • 你会超前于实际进度,在理解实现之前就敲定测试结构

正确做法:通过示踪弹进行垂直切片。一个测试 → 一个实现 → 重复。每个测试都基于上一轮的收获。由于你刚刚写完代码,因此清楚哪些行为至关重要,以及如何验证它们。

WRONG (horizontal):
  RED:   test1, test2, test3, test4, test5
  GREEN: impl1, impl2, impl3, impl4, impl5

RIGHT (vertical):
  RED→GREEN: test1→impl1
  RED→GREEN: test2→impl2
  RED→GREEN: test3→impl3
  ...

反模式:同义反复的测试

断言以与代码相同的方式重新计算预期值——expect(add(a, b)).toBe(a + b)、通过相同逻辑手动推导出的快照,或断言一个常量等于自身。这样的测试从构造上就会通过,永远无法与代码的结果产生分歧。

预期值必须来自独立的事实来源:可靠的字面值、完整算例或规范。示例见 tests.md。

工作流

0. 了解技术栈

TDD 循环具有普适性,命令则不然。在编写第一个测试前,先了解_当前_仓库如何运行测试,并在每个 RED 和 GREEN 阶段使用相应命令:

  • 构建系统:package.json、pyproject.toml、go.mod、Cargo.toml、Makefile
  • 优先使用仓库中已提交的包装器:./gradlew、./mvnw、make test、仓库脚本——绝不要使用仓库未采用的全局安装工具
  • 区分单个目标测试命令与完整测试套件命令——循环期间运行目标测试,完成前运行一次完整测试套件
  • 查明测试所在位置、命名方式,以及相邻测试遵循的模式
  • CI 工作流会显示实际用于门禁合并的命令

切勿假定使用 npm test。

1. 规划

探索代码库时,如果存在 GLOSSARY.md,请阅读它;否则阅读旧版 CONTEXT.md(在多上下文仓库中,GLOSSARY-MAP.md 会指明正确的文件),以确保测试名称和接口术语符合项目的领域语言,并遵守你正在处理区域的 ADR。

接缝是你进行测试的公共边界:在此处观察行为,而不深入内部。在编写任何测试之前,先写下要测试的接缝,每个接缝用一行说明该处的测试能捕获什么、无法捕获什么,并与用户确认:

询问:“公共接口是什么?我们应该测试哪些接缝?”

未经确认的接缝一律不编写测试。

编写任何代码之前:

  • 与用户确认要测试的接缝
  • 与用户确认要测试哪些行为(确定优先级)
  • 识别深化模块的机会(小接口、深实现)——调用 codebase-design 技能工具,了解相关术语和可测试性检查项
  • 列出要测试的行为(而非实现步骤)
  • 获得用户对计划的批准

你不可能测试所有内容。 提前就接缝达成一致,才能让测试投入聚焦于关键路径和复杂逻辑,而非每一种可能的边缘情况。

2. 示踪弹

编写一个测试,确认系统的一项功能:

RED:   Write test for first behavior → test fails
GREEN: Write minimal code to pass → test passes

这是你的示踪弹——用于证明整个端到端路径正常工作。

3. 增量循环

对于每个剩余行为:

RED:   Write next test → fails
GREEN: Minimal code to pass → passes

规则:

  • 一次只编写一个测试
  • 只编写足以通过当前测试的代码
  • 不要预先考虑未来的测试
  • 让测试聚焦于可观察的行为
4. 重构

只有在测试全绿后才能重构——测试为红时绝不重构。提取重复代码,深化模块(调用 codebase-design 技能工具,了解相关术语),并思考新代码揭示了现有代码的哪些问题。每一步之后都运行测试。

评论

支持 Markdown