369 lines
9.0 KiB
Markdown
369 lines
9.0 KiB
Markdown
本文档展示如何在 Claude 环境中严格遵循 **测试驱动开发 (TDD)** 规范。
|
||
|
||
## 必须使用简体中文(严格遵守)
|
||
## 界面(pages/components等)不写测试
|
||
## 依赖网络请求、文件请求等外部环境不写测试(mock替代)
|
||
|
||
## 🎯 TDD 核心原则 (严格遵守)
|
||
|
||
### 🔴 红阶段:编写失败测试
|
||
```typescript
|
||
// ❌ 必须先写失败的测试
|
||
describe('Calculator', () => {
|
||
it('should add two numbers', () => {
|
||
const calc = new Calculator(); // 这里会失败 - 正确的!
|
||
expect(calc.add(2, 3)).toBe(5);
|
||
});
|
||
});
|
||
```
|
||
|
||
### 🟢 绿阶段:最小实现
|
||
```typescript
|
||
// ✅ 只写刚好让测试通过的代码
|
||
export class Calculator {
|
||
add(a: number, b: number): number {
|
||
return a + b; // 最简实现
|
||
}
|
||
}
|
||
```
|
||
|
||
### 🔄 重构阶段:优化代码
|
||
```typescript
|
||
// ✅ 在绿灯状态下安全重构
|
||
export class Calculator {
|
||
/**
|
||
* 两数相加
|
||
* @param a 第一个数
|
||
* @param b 第二个数
|
||
* @returns 和
|
||
*/
|
||
add(a: number, b: number): number {
|
||
return a + b;
|
||
}
|
||
}
|
||
```
|
||
|
||
## 🚫 TDD 强制规则 (绝不违反)
|
||
|
||
### ❌ 禁止行为
|
||
- **绝对不允许**在没有测试的情况下编写生产代码
|
||
- **绝对不允许**跳过红阶段直接写实现
|
||
- **绝对不允许**在红灯状态下进行重构
|
||
- **绝对不允许**同时处理多个失败测试
|
||
- **绝对不允许**写example示例代码
|
||
- **绝对不允许**业务中写测试代码
|
||
- **绝对不允许**业务中写简化或mock代码
|
||
|
||
### ✅ 必须行为
|
||
- **必须切换新分支** 切换新的分支后开始新功能开发
|
||
- **必须确认**测试在功能实现前是失败的
|
||
- **必须编写**刚好让测试通过的最小代码
|
||
- **必须在**所有测试通过的绿灯状态下进行重构
|
||
- **必须保持**每个测试的独立性
|
||
- **必须遵守**单个文件代码行数不超过500行
|
||
- **必须遵守**环境依赖性测试(文件系统监控、网络连接、性能测试),使用模拟对象(Mock)替代真实环境依赖,确保测试的稳定性
|
||
|
||
## 🛠️ Claude TDD 工作流程
|
||
|
||
### Step 1: 需求分析 → 测试设计
|
||
```bash
|
||
# 在 Claude 中的对话流程
|
||
用户: "我需要一个计算器功能"
|
||
Claude: "让我们从测试开始。首先写一个失败的测试..."
|
||
```
|
||
|
||
### Step 2: 🔴 红阶段执行
|
||
```typescript
|
||
// 1. 先创建测试文件
|
||
// src/calculator.test.ts
|
||
import { Calculator } from './calculator'; // ❌ 这会失败
|
||
|
||
describe('Calculator', () => {
|
||
it('should add two positive numbers', () => {
|
||
const calculator = new Calculator();
|
||
expect(calculator.add(2, 3)).toBe(5);
|
||
});
|
||
});
|
||
```
|
||
|
||
```bash
|
||
# 2. 运行测试确认失败
|
||
npm run test
|
||
# ❌ Cannot find module './calculator' - 正确的失败!
|
||
```
|
||
|
||
### Step 3: 🟢 绿阶段执行
|
||
```typescript
|
||
// 3. 创建最小实现
|
||
// src/calculator.ts
|
||
export class Calculator {
|
||
add(a: number, b: number): number {
|
||
return a + b; // 最简实现
|
||
}
|
||
}
|
||
```
|
||
|
||
```bash
|
||
# 4. 运行测试确认通过
|
||
npm run test
|
||
# ✅ Tests: 1 passed, 1 total
|
||
```
|
||
|
||
### Step 4: 🔄 重构阶段执行
|
||
```typescript
|
||
// 5. 在绿灯状态下改进代码质量
|
||
export class Calculator {
|
||
/**
|
||
* 添加两个数字
|
||
* @param a 第一个数字
|
||
* @param b 第二个数字
|
||
* @returns 两数之和
|
||
*/
|
||
add(a: number, b: number): number {
|
||
// 可以添加输入验证等
|
||
if (typeof a !== 'number' || typeof b !== 'number') {
|
||
throw new Error('Both arguments must be numbers');
|
||
}
|
||
return a + b;
|
||
}
|
||
}
|
||
```
|
||
|
||
```bash
|
||
# 6. 确保重构后测试仍然通过
|
||
npm run test
|
||
# ✅ Tests: 1 passed, 1 total
|
||
```
|
||
|
||
## 📊 Claude TDD 质量检查清单
|
||
|
||
### 🔴 红阶段检查清单
|
||
- [ ] 测试用例清晰表达了期望的行为
|
||
- [ ] 测试失败的原因是功能未实现,而非测试错误
|
||
- [ ] 测试范围适中,只验证一个具体功能点
|
||
- [ ] 测试用例名称具有良好的可读性
|
||
|
||
### 🟢 绿阶段检查清单
|
||
- [ ] 所有测试都通过
|
||
- [ ] 实现代码尽可能简单
|
||
- [ ] 没有实现当前测试不需要的功能
|
||
- [ ] 代码能够正确处理测试用例的所有场景
|
||
|
||
### 🔄 重构阶段检查清单
|
||
- [ ] 消除了代码重复
|
||
- [ ] 提高了代码可读性
|
||
- [ ] 改善了代码结构
|
||
- [ ] 所有测试仍然通过
|
||
- [ ] 没有改变外部行为
|
||
|
||
## 🎓 Claude TDD 最佳实践
|
||
|
||
### 1. 对话驱动的 TDD
|
||
```
|
||
用户: "添加减法功能"
|
||
Claude: "让我们遵循 TDD 流程:
|
||
1. 🔴 先写减法的失败测试
|
||
2. 🟢 实现最小的减法功能
|
||
3. 🔄 重构优化代码"
|
||
```
|
||
|
||
### 2. 增量式开发
|
||
```typescript
|
||
// 第一个测试:基本功能
|
||
it('should subtract two positive numbers', () => {
|
||
expect(calc.subtract(5, 3)).toBe(2);
|
||
});
|
||
|
||
// 第二个测试:边界情况
|
||
it('should handle negative results', () => {
|
||
expect(calc.subtract(3, 5)).toBe(-2);
|
||
});
|
||
|
||
// 第三个测试:零值处理
|
||
it('should handle zero values', () => {
|
||
expect(calc.subtract(5, 0)).toBe(5);
|
||
});
|
||
```
|
||
|
||
### 3. 测试即文档
|
||
```typescript
|
||
describe('Calculator', () => {
|
||
describe('add method', () => {
|
||
it('should add two positive integers correctly', () => {
|
||
// 测试名称就是功能文档
|
||
});
|
||
|
||
it('should handle floating point numbers with precision', () => {
|
||
// 清晰表达预期行为
|
||
});
|
||
});
|
||
});
|
||
```
|
||
|
||
## 🚀 Claude TDD 命令速查
|
||
|
||
### 快速启动 TDD 循环
|
||
```bash
|
||
# 1. 创建测试文件
|
||
touch src/feature.test.ts
|
||
|
||
# 2. 运行测试 (红阶段)
|
||
npm run test:watch
|
||
|
||
# 3. 创建实现文件
|
||
touch src/feature.ts
|
||
|
||
# 4. 运行构建 (绿阶段后)
|
||
npm run build
|
||
|
||
# 5. 查看覆盖率
|
||
npm run test:coverage
|
||
```
|
||
|
||
### TDD 开发节奏
|
||
```bash
|
||
# 保持快速的红-绿-重构循环
|
||
🔴 写测试 → ❌ 运行测试 → 🟢 写代码 → ✅ 运行测试 → 🔄 重构 → ✅ 运行测试
|
||
```
|
||
|
||
## 📈 成功的 TDD 指标
|
||
|
||
### 代码质量指标
|
||
- ✅ **测试覆盖率**: 95%+ (强制要求)
|
||
- ✅ **测试执行时间**: < 2 秒 (快速反馈)
|
||
- ✅ **测试独立性**: 100% (无依赖测试)
|
||
- ✅ **代码重复度**: 最小化
|
||
|
||
### TDD 流程指标
|
||
- ✅ **红-绿-重构循环**: 严格遵循
|
||
- ✅ **测试先行率**: 100% (无例外)
|
||
- ✅ **最小实现原则**: 始终遵守
|
||
- ✅ **重构安全性**: 测试保护下进行
|
||
|
||
## 🎯 下一步 TDD 开发
|
||
|
||
继续使用 Claude 进行 TDD 开发时:
|
||
|
||
1. **🔴 红阶段**: 告诉 Claude 你需要什么功能,让它先写失败测试
|
||
2. **🟢 绿阶段**: 让 Claude 实现最小代码使测试通过
|
||
3. **🔄 重构阶段**: 与 Claude 一起改进代码质量
|
||
4. **重复循环**: 为每个新功能重复此过程
|
||
|
||
**记住:在 Claude 环境中,TDD 不仅是开发方法,更是确保代码质量和设计优雅的严格纪律!** 🎉
|
||
|
||
## 💡 Claude TDD 实战示例
|
||
|
||
### 示例:添加乘法功能
|
||
|
||
#### 🔴 红阶段:用户请求
|
||
```
|
||
用户: "我需要添加乘法功能"
|
||
Claude: "好的,让我们严格遵循 TDD 流程。首先写一个失败的测试:"
|
||
```
|
||
|
||
#### 测试代码 (先写)
|
||
```typescript
|
||
// src/calculator.test.ts
|
||
describe('Calculator', () => {
|
||
// ... 现有测试 ...
|
||
|
||
describe('multiply', () => {
|
||
it('should multiply two positive numbers correctly', () => {
|
||
const calculator = new Calculator();
|
||
expect(calculator.multiply(3, 4)).toBe(12); // ❌ 这会失败
|
||
});
|
||
});
|
||
});
|
||
```
|
||
|
||
#### 🟢 绿阶段:最小实现
|
||
```typescript
|
||
// src/calculator.ts
|
||
export class Calculator {
|
||
add(a: number, b: number): number {
|
||
return a + b;
|
||
}
|
||
|
||
multiply(a: number, b: number): number {
|
||
return a * b; // 最简实现
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 🔄 重构阶段:优化代码
|
||
```typescript
|
||
export class Calculator {
|
||
/**
|
||
* 两数相加
|
||
*/
|
||
add(a: number, b: number): number {
|
||
return a + b;
|
||
}
|
||
|
||
/**
|
||
* 两数相乘
|
||
* @param a 被乘数
|
||
* @param b 乘数
|
||
* @returns 乘积
|
||
*/
|
||
multiply(a: number, b: number): number {
|
||
return a * b;
|
||
}
|
||
}
|
||
```
|
||
|
||
## 🔧 Claude TDD 故障排除
|
||
|
||
### 常见问题与解决方案
|
||
|
||
#### 问题 1: 测试没有失败
|
||
```typescript
|
||
// ❌ 错误:测试一开始就通过了
|
||
it('should return true', () => {
|
||
expect(true).toBe(true); // 这不是有效的 TDD 测试
|
||
});
|
||
|
||
// ✅ 正确:测试应该验证具体功能
|
||
it('should validate email format', () => {
|
||
const validator = new EmailValidator();
|
||
expect(validator.isValid('test@example.com')).toBe(true); // 会失败,因为类不存在
|
||
});
|
||
```
|
||
|
||
#### 问题 2: 实现过度复杂
|
||
```typescript
|
||
// ❌ 错误:过度实现
|
||
multiply(a: number, b: number): number {
|
||
// 不需要的复杂逻辑
|
||
if (a === 0 || b === 0) return 0;
|
||
if (a === 1) return b;
|
||
if (b === 1) return a;
|
||
// ... 更多不必要的逻辑
|
||
return a * b;
|
||
}
|
||
|
||
// ✅ 正确:最小实现
|
||
multiply(a: number, b: number): number {
|
||
return a * b; // 简单直接
|
||
}
|
||
```
|
||
|
||
#### 问题 3: 在红灯状态下重构
|
||
```bash
|
||
# ❌ 错误流程
|
||
npm run test # ❌ 测试失败
|
||
# 开始重构代码 <- 错误!应该先让测试通过
|
||
|
||
# ✅ 正确流程
|
||
npm run test # ❌ 测试失败
|
||
# 写最小代码让测试通过
|
||
npm run test # ✅ 测试通过
|
||
# 现在可以安全重构
|
||
```
|
||
|
||
### 关键文件说明
|
||
- `jest.config.js` - 测试框架配置
|
||
- `tsconfig.json` - TypeScript 严格模式配置
|
||
- `package.json` - TDD 相关脚本命令
|
||
- `src/*.test.ts` - 测试文件 (TDD 的核心)
|