关于 tdd
tdd 是指导测试驱动开发的 Skill,强调通过公共接口验证可观察行为,并以单个测试和最小实现逐步推进。它还要求先确认接口、测试重点和设计边界,再开始实现。
主要功能
- 01通过公共接口测试行为
- 02按单个测试逐步推进 RED→GREEN
- 03每轮只实现当前测试所需代码
- 04避免一次性编写全部测试
- 05全部通过后再进行重构
适用场景
- 01为新功能按用户行为逐步编写测试
- 02检查测试是否依赖内部实现
- 03在设计边界未明确时暂停实现
- 04测试通过后交由后续阶段清理代码
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ carlitose/ agent-skills --skill tdd安装后在 Claude Code 中输入/tdd确认已加载。
附带文件mocking.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. 规划
开始编写代码之前:
- 与用户确认需要哪些接口变更
- 与用户确认要测试哪些行为(并确定优先级)
- 使用 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. 重构
所有测试通过后,将有针对性的清理工作交给 code-simplification,然后将冻结的候选版本交给 code-review。TDD 不负责这两个质量阶段, 也不重复它们的检查清单。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