name: tdd-workflow description: 测试驱动开发工作流强制执行,采用RED-GREEN-REFACTOR周期。用于在实现功能时测试优先或提高测试覆盖率。
测试驱动开发(TDD)工作流
一种纪律严明的开发方法,测试驱动设计和实现。
TDD 箴言
“永远不要在没有失败测试的情况下写一行代码。”
RED-GREEN-REFACTOR 循环
RED 阶段:写一个失败的测试
目标:在实现之前定义预期行为。
规则:
- 写一个最小的失败测试
- 测试必须因正确原因失败
- 测试应清晰地表达意图
- 不要写实现代码
示例:
// RED:测试我们想要的行为
describe("Calculator", () => {
it("should add two numbers", () => {
const calc = new Calculator();
expect(calc.add(2, 3)).toBe(5);
});
});
// 运行:npm test
// 结果:失败 - Calculator 未定义
// 这是 RED ✓
检查清单:
- [ ] 测试已写
- [ ] 测试运行失败
- [ ] 失败信息清晰
- [ ] 测试名称描述预期行为
GREEN 阶段:使测试通过
目标:写最少的代码使测试通过。
规则:
- 做最简单可行的事
- 不要添加额外功能
- 不要优化
- 只让它变绿
示例:
// GREEN:通过测试的最小实现
class Calculator {
add(a: number, b: number): number {
return a + b; // 最简单可行的事
}
}
// 运行:npm test
// 结果:通过
// 这是 GREEN ✓
检查清单:
- [ ] 测试通过
- [ ] 未添加额外代码
- [ ] 实现是最小的
REFACTOR 阶段:改进代码
目标:清理代码,同时保持测试通过。
规则:
- 只在测试通过时重构
- 每次更改后运行测试
- 改进设计,而不是行为
- 小步、增量更改
重构示例:
- 提取方法
- 重命名以提高清晰度
- 去除重复
- 提高性能
- 添加类型/文档
检查清单:
- [ ] 测试仍然通过
- [ ] 代码更整洁
- [ ] 行为未改变
- [ ] 准备好下一个 RED
TDD 实践
开始新功能
1. 写高层次验收测试(可能尚未运行)
2. 写第一个单元测试(RED)
3. 实现最小代码(GREEN)
4. 如果需要,重构(REFACTOR)
5. 重复 2-4 直到功能完成
6. 验证验收测试通过
测试结构(AAA 模式)
it("should [行为] when [条件]", () => {
// Arrange - 设置测试数据和依赖
const user = createTestUser({ role: "admin" });
const service = new UserService();
// Act - 执行被测试代码
const result = service.getPermissions(user);
// Assert - 验证预期结果
expect(result).toContain("delete");
expect(result).toContain("edit");
});
测试命名约定
[单元]_[场景]_[预期结果]
示例:
add_withPositiveNumbers_returnsSumlogin_withInvalidPassword_throwsAuthErrorgetUser_whenNotFound_returnsNull
测试类别
单元测试
- 单个函数/类在隔离环境中
- 模拟所有依赖
- 快速(<10ms 每个测试)
- 在开发期间持续运行
集成测试
- 多个组件一起
- 真实数据库(测试实例)
- 较慢但更现实
- 提交前运行
端到端测试
- 通过UI的完整系统
- 最慢,最现实
- 在CI/CD管道中运行
- 覆盖关键用户路径
TDD 最佳实践
要做:
- 从最简单情况开始
- 一次写一个测试
- 保持测试独立
- 测试行为,而不是实现
- 使用描述性测试名称
- 每次变绿后提交
不要做:
- 在测试前写代码
- 直接测试私有方法
- 测试框架代码
- 过度适应测试到实现
- 跳过重构阶段
要测试的边缘情况
始终测试:
- 空输入(null, undefined, [], {}, ‘’)
- 边界值(0, -1, MAX_INT, 最小/最大日期)
- 错误条件(网络失败,无效输入)
- 权限边界
- 并发访问
- Unicode/特殊字符
测试覆盖率指南
| 指标 | 最低 | 目标 |
|---|---|---|
| 语句覆盖率 | 70% | 85% |
| 分支覆盖率 | 70% | 80% |
| 函数覆盖率 | 80% | 90% |
| 行覆盖率 | 70% | 85% |
覆盖率是指标,不是目标。100% 覆盖率不意味着无错误。
快速参考
RED → 写失败测试(定义行为)
GREEN → 最少代码通过(让它工作)
REFACTOR → 清理代码(让它正确)
COMMIT → 保存进度(让它永久)
常见 TDD 错误
| 错误 | 问题 | 解决方案 |
|---|---|---|
| 测试实现 | 脆弱测试 | 测试行为/结果 |
| 测试太大 | 难以调试 | 更小、专注的测试 |
| 共享状态 | 不稳定测试 | 隔离每个测试 |
| 慢测试 | 被跳过的测试 | 模拟外部依赖 |
| 测试明显代码 | 浪费时间 | 专注于逻辑 |