mcpskills.net
技能MCP智能体提示词
mcpskills.net — A curated directory of AI agent Skills and MCP servers
TermsPrivacy
← 返回技能
Engineering

测试驱动开发(Matt Pocock)

测试驱动开发。当用户希望以测试优先的方式构建功能或修复 Bug、提到 'red-green-refactor',或需要集成测试时使用。

作者:Matt Pocock仓库 →来源 →

测试驱动开发

理念

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

好的测试 是集成风格的:它们通过公共 API 走完真实的代码路径。它们描述系统 做了什么,而非系统 如何做。一个好的测试读起来就像一份规格说明——"用户可以用有效的购物车结账"准确地告诉你存在什么能力。这些测试能够在重构中存活,因为它们不关心内部结构。

坏的测试 与实现紧密耦合。它们 Mock 内部协作者、测试私有方法,或通过外部手段进行验证(比如直接查询数据库,而不是使用接口)。警示信号是:当你重构时测试失败了,但行为并没有改变。如果你重命名了一个内部函数而测试失败,那么这些测试测的是实现,而非行为。

反模式:水平切片

不要先编写所有测试,然后再编写所有实现。 这就是"水平切片"——把 RED 理解为"编写所有测试",把 GREEN 理解为"编写所有代码"。

这会产生 糟糕的测试:

  • 成批编写的测试测的是 想象出来的 行为,而非 实际的 行为
  • 你最终测的是事物的 形状(数据结构、函数签名),而非面向用户的行为
  • 测试对真实的变更变得不敏感——行为出错时它们通过,行为正常时它们却失败
  • 你超出了自己的视野范围,在理解实现之前就锁定了测试结构

正确的做法:通过曳光弹(tracer bullets)进行垂直切片。一个测试 → 一个实现 → 重复。每个测试都回应你从上一个循环中学到的东西。因为你刚刚写完代码,所以你确切知道哪些行为重要以及如何验证它。

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(架构决策记录)。

在编写任何代码之前:

  • [ ] 与用户确认需要哪些接口变更
  • [ ] 与用户确认要测试哪些行为(确定优先级)
  • [ ] 识别深模块的机会(小接口,深实现)
  • [ ] 列出要测试的行为(而非实现步骤)
  • [ ] 获得用户对计划的批准

询问:"公共接口应该是什么样子?哪些行为最需要测试?"

你无法测试所有东西。 与用户确认到底哪些行为最重要。把测试精力集中在关键路径和复杂逻辑上,而不是每一种可能的边界情况。

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