Commandgeneral
/tdd Command
使用测试驱动开发方法实现:$ARGUMENTS
TDD 测试驱动开发
使用测试驱动开发方法实现:$ARGUMENTS
TDD 核心循环
🔴 RED - 编写失败的测试
-
理解需求
- 明确功能的输入和输出
- 定义边界条件和异常情况
- 确定成功标准
-
编写测试
// 示例结构 describe('功能名称', () => { it('应该在[条件]时[预期行为]', () => { // Arrange - 准备测试数据 // Act - 执行被测试的功能 // Assert - 验证结果 }); }); -
验证测试失败
- 运行测试确保失败(重要!)
- 失败原因应该是"功能未实现"
- 不要写任何实现代码
🟢 GREEN - 编写通过测试的代码
-
最简实现
- 写最少的代码让测试通过
- 不考虑优化和优雅
- 专注于功能正确性
-
运行测试
- 确保新写的测试通过
- 确保已有测试仍然通过
- 如果失败,修复代码(不改测试)
-
提交代码
- 测试和实现一起提交
- 提交信息说明实现的功能
🔵 REFACTOR - 重构优化
-
改善代码结构
- 消除重复代码
- 提取函数或常量
- 改善命名和可读性
-
保持测试通过
- 每次小改动后运行测试
- 确保功能没有被破坏
- 可以调整测试结构(不改逻辑)
-
性能优化(如需要)
- 只在确实需要时优化
- 先测量,后优化
- 保持代码可读性
执行步骤
步骤 1: 分析需求
- [ ] 理解要实现的功能
- [ ] 列出所有测试场景
- [ ] 确定输入输出格式
步骤 2: 编写第一个测试
- [ ] 选择最简单的场景
- [ ] 编写清晰的测试描述
- [ ] 实现测试逻辑
- [ ] 运行并确认失败
步骤 3: 实现功能
- [ ] 编写最简代码通过测试
- [ ] 不添加额外功能
- [ ] 运行测试确认通过
步骤 4: 添加更多测试
- [ ] 覆盖正常场景
- [ ] 覆盖边界条件
- [ ] 覆盖错误处理
- [ ] 每个测试重复 RED-GREEN-REFACTOR
步骤 5: 重构和优化
- [ ] 识别重复代码
- [ ] 提取共享逻辑
- [ ] 改善代码结构
- [ ] 确保所有测试通过
最佳实践
测试命名
// ✅ 好的命名 - 描述行为
it('should return user name when user exists')
it('should throw error when user not found')
// ❌ 差的命名 - 太模糊
it('test user')
it('works correctly')
测试独立性
- 每个测试独立运行
- 不依赖其他测试的状态
- 使用 beforeEach/afterEach 重置状态
测试覆盖
- 正常路径(Happy Path)
- 边界条件(空值、极值)
- 错误情况(异常、无效输入)
- 并发场景(如适用)
断言原则
// 一个测试一个断言(理想情况)
it('should calculate total price', () => {
const result = calculateTotal(items);
expect(result).toBe(100);
});
// 相关的多个断言可以接受
it('should return complete user object', () => {
const user = getUser(1);
expect(user.id).toBe(1);
expect(user.name).toBeDefined();
expect(user.email).toMatch(/@/);
});
常见错误
❌ 避免这些错误
- 跳过 RED 阶段 - 直接写实现代码
- 修改测试来通过 - 应该修改实现
- 写太多代码 - 超出测试要求的范围
- 延迟重构 - 积累技术债务
- 测试实现细节 - 应该测试行为
✅ 正确的做法
- 严格遵循 RED-GREEN-REFACTOR
- 保持测试简单明了
- 小步前进,频繁提交
- 测试行为,不测试实现
- 及时重构,保持代码整洁
示例工作流
# 1. 创建测试文件
touch test/feature.test.js
# 2. 编写第一个失败的测试
npm test -- --watch
# 3. 实现功能让测试通过
# ... 编码 ...
# 4. 运行所有测试
npm test
# 5. 重构代码
# ... 重构 ...
# 6. 确认测试仍然通过
npm test
# 7. 提交代码
git add .
git commit -m "feat: implement feature using TDD"
记住
"TDD 不是关于测试,而是关于设计。通过先写测试,我们被迫思考接口和行为,而不是实现细节。" - Kent Beck
使用 TDD 的目标不仅是编写测试,更是:
- 🎯 驱动更好的设计
- 🛡️ 建立信心安全网
- 📖 创建活文档
- 🔄 支持持续重构