关于 tdd
tdd 是一项跨语言和测试框架的测试驱动开发 Agent 技能,强调通过稳定边界验证可观察行为。它采用逐项 RED–GREEN 循环,并要求在改代码前厘清需求约定。
主要功能
- 01在稳定边界测试可观察行为
- 02逐项执行 RED–GREEN 循环
- 03遵循项目语言与测试惯例
- 04编辑前检查需求约定
- 05覆盖失败场景和边界情况
适用场景
- 01逐步开发功能
- 02复现并修复已报告的问题
- 03避免测试依赖实现细节
- 04区分回归与既有测试失败
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ hburaktasyurek/ agent-skills-and-commands --skill tdd安装后在 Claude Code 中输入/tdd确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
deep-modules.mdinterface-design.mdmocking.mdrefactoring.mdtests.mdagents/openai.yaml详细介绍
测试驱动开发
理念
核心原则:测试应通过最稳定的可用契约边界验证可观察行为,而不是验证偶然的实现细节。代码可以彻底改变;除非行为发生变化,否则测试不应失败。
好的测试采用集成测试风格:通过公共 API 执行真实代码路径。它们描述系统_做什么_,而不是_如何_实现。好的测试读起来就像一份规范——“用户可以使用有效购物车完成结账”准确说明了系统具备什么能力。这类测试能经受重构,因为它们不关心内部结构。
糟糕的测试与实现耦合。它们模拟内部协作者、测试私有方法,或断言偶然的调用顺序。警示信号:仅仅重命名或调整不影响行为的内部结构,测试就会失败。
公共响应并不总是充分的证据。持久化、幂等性、并发、队列和恢复契约可能需要启动新进程、使用独立连接、在提交后读取,或断言持久状态。如果这类证据属于可观察契约,就应使用它;不要用成功响应或模拟交互代替真正的不变量。
参见 tests.md 了解示例,参见 mocking.md 了解模拟指南。
语言与工具
这里的原则——关注行为而非实现、仅在系统边界进行模拟、深模块——与语言无关。示例仅用于说明,使用的是 TypeScript/Jest。**编写任何测试前,先检测项目所用的语言、测试运行器、断言风格和模拟约定,并遵循这些约定。**转换原则,而不是语法:Python 项目使用 pytest 的惯用写法和 fixtures,PHP 项目遵循 PHPUnit 约定,JS/TS 项目使用现有的测试运行器(Jest/Vitest/node:test)。不要将某种语言的惯用写法带入未使用它的项目。
反模式:水平切片
**不要先写完所有测试,再写完所有实现。**这就是“水平切片”——把 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
...
契约关卡
编辑前,先阅读仓库说明和权威任务、简报、规范或审查发现。检查足够多的实现与测试,以判断契约是否已准备就绪。
- 如果行为、范围、公共接口、验收标准和决策权均已明确,就将其视为已获批准,并开始第一个 RED 周期。不要要求用户再次确认计划,或重复已有产物中已经作出的决定。
- 如果技术细节不会改变产品行为或范围,就根据仓库证据解决。
- 如果产物相互冲突,或仍有重要的行为、范围、接口、优先级或决策权尚未确定,就不要写入仓库。报告证据冲突,并提出一个具体的阻塞性问题。
- 如果直接请求具有权威性且内容完整,不要因为缺少流程形式——例如工单、路线图或单独的测试计划——就将其作为阻塞因素。
列出为实现因果闭环所需的最小有序行为集,包括失败模式和边界。将其作为执行指南;除非契约关卡发现确实需要人工决策的问题,否则不要暂停等待批准。
工作流
1. 首先 RED
对于功能,请从已批准的契约中选择最精简的端到端行为。对于 Bug,先在能够证明 Bug 的边界复现所报告的故障。
编写一个聚焦的测试并运行。只有当测试因预期缺失或错误的行为而失败时,RED 才有效。语法错误、损坏的测试夹具、不可用的依赖项或无关的既有故障都不能作为有效的 RED;应修复测试设置,或报告外部阻碍,不要更改产品代码。
你无法测试所有内容,但“关键行为”包括系统如何失败,而不仅仅是成功路径。 根据权威契约和仓库风险证据确定优先级。将错误处理、无效输入、边界条件和故障模式视为一等行为。只有在契约关卡发现真正尚未解决的决策时,才询问用户。跳过琐碎的排列组合,而不是不同的异常路径。
2. GREEN
实施最小且从根本上正确的更改,使聚焦的行为通过,同时不违反已知契约。“最小”并不意味着只修补报告问题的那一行,却让同一因果路径仍然敞开。
RED: Write test for first behavior → test fails
GREEN: Write minimal code to pass → test passes
这是你的示踪弹,证明该路径能够端到端运行。
继续之前,运行聚焦的测试并确认 GREEN。
3. 增量循环
对于每项剩余行为:
RED: Write next test → fails
GREEN: Minimal code to pass → passes
规则:
- 一次只编写一个测试
- 只编写足以通过当前测试的代码
- 不要预先考虑未来的测试
- 让测试聚焦于可观察的行为
- 根据上一轮中获得的证据添加下一个测试
- 在宣称完成之前,覆盖任务涉及的成功、失败、边界及同根因回归场景
4. 重构
所有测试通过后,查找重构候选项:
- 提取重复代码
- 深化模块(将复杂性移至简单接口之后)
- 在适当时应用 SOLID 原则
- 思考新代码揭示了现有代码的哪些问题
- 每一步重构后都运行测试
RED 时绝不重构。 先达到 GREEN。
聚焦测试循环全部通过后,运行相关的更大范围测试套件。将无关的既有故障与任务引入的回归区分开;不要悄悄修复或掩盖无关故障。
每轮检查清单
[ ] Test describes behavior, not implementation
[ ] Test uses the stable observable boundary
[ ] Test would survive internal refactor
[ ] RED failed for the expected reason
[ ] Code is minimal for this test
[ ] No speculative features added