测试驱动开发
TDD 是红→绿循环。此技能是使该循环产生值得保留的测试的参考:什么是一个好测试、测试放在哪里、反模式以及循环的规则。每个部分在每个周期都适用:在循环之前和期间查阅它们,而不是之后。
在探索代码库时,阅读 CONTEXT.md(如果存在),以便测试名称和接口词汇与项目的领域语言匹配,并尊重您所接触区域的 ADR。
什么是一个好测试
测试通过公共接口验证行为,而非实现细节。代码可以完全改变;测试不应改变。一个好测试读起来像一份规范:“用户可以凭有效购物车结账”准确地告诉您存在什么能力,并且它能在重构中存活,因为它不关心内部结构。
参见 tests.md 获取示例,以及 mocking.md 获取模拟指南。
接缝:测试的位置
接缝是您进行测试的公共边界:您在不深入内部的情况下观察行为的接口。测试位于接缝处,永远不要针对内部实现。
仅在预先商定的接缝处进行测试。 在编写任何测试之前,写下正在测试的接缝并与用户确认。未确认的接缝不得编写测试。您不可能测试所有内容,因此提前商定接缝是为了将测试工作集中在关键路径和复杂逻辑上,而不是每个边缘情况。
询问:“公共接口是什么,我们应该测试哪些接缝?”
当接口的形状本身存疑时(模块有多深、接缝属于哪里、接口应该暴露什么),请使用“codebase-design”技能工具调用相应的词汇。它是关于模块、接口、深度、接缝、适配器、杠杆和局部性术语的共享来源,是一个可供参考的参考,而不是一个要运行的会话。
反模式
- 与实现耦合:模拟内部协作对象、测试私有方法,或通过侧通道验证(查询数据库而不是使用接口)。迹象:重构时测试失败,但行为未改变。
- 同义反复:断言重新计算期望值的方式与代码相同(
expect(add(a, b)).toBe(a + b)、以相同方式手动推导的快照、断言等于自身的常量),因此它通过构造而永远不会与代码矛盾。期望值必须来自独立的真实来源:已知正确的字面量、工作示例、规范。 - 水平切片:先编写所有测试,然后编写所有实现。批量测试验证的是 想象中的 行为:您测试的是事物的 形状 而非用户面对的行为,测试对真实变化不敏感,并且在理解实现之前就确定了测试结构。取而代之的是 垂直切片 工作方式:一个测试 → 一个实现 → 重复,每个测试都是一颗 示踪子弹,回应上一个循环教给您的经验。
循环的规则
- 红先于绿。先编写失败的测试,然后只编写足够的代码使其通过。不要预期未来的测试或添加推测性功能。
- 一次一个切片。每个周期一个接缝、一个测试、一个最小实现。
- 重构不属于循环。它属于审查阶段(参见
matt-code-review技能),而不是红→绿实现周期。