测试驱动开发
一次构建一个垂直切片的功能并修复错误,将测试作为反馈循环。
核心原则
测试通过公共接口验证行为,而非实现细节。如果你重构后,测试在没有改变行为的情况下失败,那么测试本身是错误的。
反模式:水平切片
不要先编写所有测试,然后再编写所有实现。而是编写一个测试,使其通过,然后重复。
错误: RED test1, test2, test3 -> GREEN impl1, impl2, impl3
正确: RED test1 -> GREEN impl1 -> RED test2 -> GREEN impl2 -> ...
工作流程
1. 计划
- 与用户确认接口变更。
- 确认要测试哪些行为。你无法测试所有内容。
- 将行为列为可观察到的结果,而非实现步骤。
- 在编写代码之前获取用户批准。
2. 单步走通
为一个行为编写一个测试。观察其失败。编写使其通过的最少代码。
3. 增量循环
对于每个剩余行为:
- 编写下一个测试。
- 使用最少的代码使其通过。
- 不要预判未来的测试。
4. 重构
在所有测试通过后:
- 提取重复代码。
- 深化模块:窄接口,深实现。
- 每次重构步骤后运行测试。
切勿在测试失败时重构。
每个周期的检查清单
- 测试描述的是行为,而非实现。
- 测试使用公共接口。
- 测试能够经受住内部重构。
- 代码对于此测试来说是最少的。
- 没有添加推测性功能。
规则
- 在实现新行为之前编写测试。
- 使用类型提示和清晰的名称。
- 保持函数小巧且单一职责。
- 快速失败并给出清晰的错误消息。