关于 tdd
面向编码 Agent 的 TDD 技能,强调通过公开接口验证行为,并逐个测试推进实现。它采用递增式 RED–GREEN 循环,并要求测试通过后再重构。
主要功能
- 01通过公开接口测试
- 02递增式 RED–GREEN 循环
- 03围绕行为规划测试
- 04仅在 GREEN 后重构
- 05本地替身与接缝规范
适用场景
- 01围绕用户可见行为规划测试
- 02以小步测试循环实现功能
- 03检查测试是否耦合实现细节
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dmmulroy/ skills --skill tdd安装后在 Claude Code 中输入/tdd确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
mocking.mdrefactoring.mdtests.md详细介绍
测试驱动开发
理念
核心原则:测试应通过公共接口验证行为,而不是实现细节。代码可以彻底改变;测试不应改变。
好的测试采用集成式风格:它们通过公共 API 执行真实的代码路径。它们描述系统_做什么_,而不是_如何_做。好的测试读起来就像一份规范——“用户可以使用有效购物车结账”清楚地说明了系统具备什么能力。这类测试经得住重构,因为它们不关心内部结构。
糟糕的测试与实现紧密耦合。它们模拟内部协作者、测试私有方法,或通过外部方式验证(例如直接查询数据库,而不是使用接口)。警示信号:重构时测试失败,但行为并未改变。如果你重命名一个内部函数,测试就失败了,那么这些测试测的是实现,而不是行为。
示例请参阅 tests.md,模拟指南请参阅 mocking.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
...
工作流
1. 规划
探索代码库时,阅读 CONTEXT.md(如果存在),确保测试名称和接口术语符合项目的领域语言,并遵循你正在修改区域的 ADR。
编写任何代码之前:
- 与用户确认需要哪些接口变更
- 与用户确认要测试哪些行为(确定优先级)
- 找出适合构建深层模块的机会(小接口、深实现)——设计和可测试性标准请参阅
../coding-standards/SKILL.md - 列出要测试的行为(而非实现步骤)
- 获取用户对计划的批准
询问:“公共接口应该是什么样的?哪些行为最重要、最需要测试?”
你不可能测试所有内容。 与用户确认哪些行为最重要。将测试精力集中在关键路径和复杂逻辑上,而不是所有可能的边缘情况。
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. 重构
所有测试通过后,查找重构候选项:
- 提取重复代码
- 深化模块(将复杂性移到简单接口之后)
- 在合适的地方应用 SOLID 原则
- 思考新代码揭示了现有代码的哪些问题
- 每次重构后运行测试
RED 阶段绝不重构。 先达到 GREEN。
每轮检查清单
[ ] Test describes behavior, not implementation
[ ] Test uses public interface only
[ ] Test would survive internal refactor
[ ] Code is minimal for this test
[ ] No speculative features added
本地覆盖规则(dmmulroy/skills)
此技能从 mattpocock/skills 引入。在此代码仓库中,
../coding-standards/SKILL.md 是权威来源,若与 mocking.md 存在冲突,则以其为准:
- 不要使用模块替换 API(
vi.mock、jest.mock)或方法间谍 API (vi.spyOn、jest.spyOn)。请通过真实的替换点来替换行为 (注入构造函数的依赖、Effect 服务/层、记录型伪适配器、 本地数据库、运行时绑定)。 - 即使在系统边界,也应优先使用通过生产替换点提供的记录型伪对象,而非模拟对象。
- 让证据与风险相匹配;对于依赖数据库或运行时的主张,应使用有代表性的数据库或运行时。