TDD 命令¶
该命令调用 tdd-guide 代理来强制执行测试驱动开发方法论。
该命令的作用¶
- 接口脚手架 - 先定义类型/接口
- 先创建测试 - 编写失败的测试(RED)
- 实现最少代码 - 只编写足以通过的代码(GREEN)
- 重构 - 在保持测试通过的同时改进代码(REFACTOR)
- 检查覆盖率 - 确保测试覆盖率在 80% 以上
使用时机¶
应当使用 /tdd 的情况:
- 实现新功能
- 添加新函数/组件
- 修复 Bug(先编写能重现 Bug 的测试)
- 重构现有代码
- 实现核心业务逻辑
工作方式¶
tdd-guide 代理执行以下操作:
- 对输入/输出进行接口定义
- (因为代码尚不存在)编写失败的测试
- 运行测试并确认是否因正确的原因失败
- 编写最小实现以使测试通过
- 运行测试并确认是否通过
- 在保持测试通过的同时重构代码
- 检查覆盖率,如果低于 80% 则补充测试
TDD 循环¶
RED → GREEN → REFACTOR → REPEAT
RED: 실패하는 테스트 작성
GREEN: 통과할 최소한의 코드 작성
REFACTOR: 코드 개선, 테스트 계속 통과 유지
REPEAT: 다음 기능/시나리오
使用示例¶
User: /tdd 마켓 유동성 점수를 계산하는 함수가 필요합니다
Agent (tdd-guide):
# TDD 세션: 마켓 유동성 점수 계산기
## 1단계: 인터페이스 정의 (SCAFFOLD)
```typescript
// lib/liquidity.ts
export interface MarketData {
totalVolume: number
bidAskSpread: number
activeTraders: number
lastTradeTime: Date
}
export function calculateLiquidityScore(market: MarketData): number {
// TODO: 구현
throw new Error('Not implemented')
}
```
## 2단계: 실패하는 테스트 작성 (RED)
```typescript
// lib/liquidity.test.ts
import { calculateLiquidityScore } from './liquidity'
describe('calculateLiquidityScore', () => {
it('should return high score for liquid market', () => {
const market = {
totalVolume: 100000,
bidAskSpread: 0.01,
activeTraders: 500,
lastTradeTime: new Date()
}
const score = calculateLiquidityScore(market)
expect(score).toBeGreaterThan(80)
expect(score).toBeLessThanOrEqual(100)
})
it('should return low score for illiquid market', () => {
const market = {
totalVolume: 100,
bidAskSpread: 0.5,
activeTraders: 2,
lastTradeTime: new Date(Date.now() - 86400000) // 1일 전
}
const score = calculateLiquidityScore(market)
expect(score).toBeLessThan(30)
expect(score).toBeGreaterThanOrEqual(0)
})
it('should handle edge case: zero volume', () => {
const market = {
totalVolume: 0,
bidAskSpread: 0,
activeTraders: 0,
lastTradeTime: new Date()
}
const score = calculateLiquidityScore(market)
expect(score).toBe(0)
})
})
```
## 3단계: 테스트 실행 - 실패 확인
```bash
npm test lib/liquidity.test.ts
FAIL lib/liquidity.test.ts
✕ should return high score for liquid market (2 ms)
Error: Not implemented
1 test failed, 0 passed
```
PASS: 예상대로 테스트 실패. 구현 준비 완료.
## 4단계: 최소한의 코드 구현 (GREEN)
```typescript
// lib/liquidity.ts
export function calculateLiquidityScore(market: MarketData): number {
// 거래량 0인 엣지 케이스 처리
if (market.totalVolume === 0) {
return 0
}
// 구성 요소별 점수 계산 (0-100 스케일)
const volumeScore = Math.min(market.totalVolume / 1000, 100)
const spreadScore = Math.max(100 - (market.bidAskSpread * 1000), 0)
const traderScore = Math.min(market.activeTraders / 10, 100)
// 최근 활동 보너스
const hoursSinceLastTrade = (Date.now() - market.lastTradeTime.getTime()) / (1000 * 60 * 60)
const recencyScore = Math.max(100 - (hoursSinceLastTrade * 10), 0)
// 가중 평균
const score = (
volumeScore * 0.4 +
spreadScore * 0.3 +
traderScore * 0.2 +
recencyScore * 0.1
)
return Math.min(Math.max(score, 0), 100) // 0-100으로 클램핑
}
```
## 5단계: 테스트 실행 - 통과 확인
```bash
npm test lib/liquidity.test.ts
PASS lib/liquidity.test.ts
✓ should return high score for liquid market (3 ms)
✓ should return low score for illiquid market (2 ms)
✓ should handle edge case: zero volume (1 ms)
3 tests passed
```
PASS: 모든 테스트 통과!
## 6단계: 리팩토링 (IMPROVE)
```typescript
// lib/liquidity.ts - 상수와 가독성 향상을 위한 리팩토링
const WEIGHTS = {
VOLUME: 0.4,
SPREAD: 0.3,
TRADERS: 0.2,
RECENCY: 0.1,
} as const
const SCALE_FACTORS = {
VOLUME: 1000,
SPREAD: 1000,
TRADERS: 10,
RECENCY_PENALTY: 10,
} as const
function clamp(value: number, min: number, max: number): number {
return Math.min(Math.max(value, min), max)
}
export function calculateLiquidityScore(market: MarketData): number {
if (market.totalVolume === 0) return 0
const volumeScore = Math.min(market.totalVolume / SCALE_FACTORS.VOLUME, 100)
const spreadScore = clamp(100 - (market.bidAskSpread * SCALE_FACTORS.SPREAD), 0, 100)
const traderScore = Math.min(market.activeTraders / SCALE_FACTORS.TRADERS, 100)
const hoursSinceLastTrade = (Date.now() - market.lastTradeTime.getTime()) / (1000 * 60 * 60)
const recencyScore = clamp(100 - (hoursSinceLastTrade * SCALE_FACTORS.RECENCY_PENALTY), 0, 100)
const weightedScore =
volumeScore * WEIGHTS.VOLUME +
spreadScore * WEIGHTS.SPREAD +
traderScore * WEIGHTS.TRADERS +
recencyScore * WEIGHTS.RECENCY
return clamp(weightedScore, 0, 100)
}
```
## 7단계: 테스트가 여전히 통과하는지 확인
```bash
npm test lib/liquidity.test.ts
PASS lib/liquidity.test.ts
✓ should return high score for liquid market (3 ms)
✓ should return low score for illiquid market (2 ms)
✓ should handle edge case: zero volume (1 ms)
3 tests passed
```
PASS: 리팩토링 완료, 테스트 여전히 통과!
## 8단계: 커버리지 확인
```bash
npm test -- --coverage lib/liquidity.test.ts
File | % Stmts | % Branch | % Funcs | % Lines
---------------|---------|----------|---------|--------
liquidity.ts | 100 | 100 | 100 | 100
Coverage: 100% PASS: (목표: 80%)
```
PASS: TDD 세션 완료!
TDD 最佳实践¶
应该做的事: - 在实现之前先编写测试 - 在实现之前运行测试,确认其失败 - 只编写足以让测试通过的最少代码 - 仅在测试通过后进行重构 - 添加边界情况和错误场景 - 目标覆盖率 80% 以上(核心代码 100%)
不应做的事: - 在测试之前编写实现 - 每次更改后跳过测试运行 - 一次编写过多代码 - 忽略失败的测试 - 测试实现细节(应测试行为) - 对所有内容进行 mock(更倾向集成测试)
包含的测试类型¶
单元测试(函数级别): - 正常路径场景 - 边界情况(空值、null、最大值) - 错误条件 - 边界值
集成测试(组件级别): - API 端点 - 数据库操作 - 外部服务调用 - 包含 hooks 的 React 组件
端到端测试(使用 /e2e 命令):
- 核心用户流程
- 多步骤流程
- 全栈集成
覆盖率要求¶
- 最低 80% - 针对所有代码
- 必须 100% - 针对以下项目:
- 金融计算
- 认证逻辑
- 安全关键代码
- 核心业务逻辑
重要事项¶
必需:测试必须在实现之前编写。TDD 循环如下:
- RED - 编写失败的测试
- GREEN - 编写实现,使测试通过
- REFACTOR - 改进代码
绝对不要跳过 RED 阶段。绝对不要在测试之前编写代码。
与其他命令的联动¶
- 首先使用
/plan理解要构建什么 - 使用
/tdd配合测试进行实现 - 发生构建错误时使用
/build-fix修复 - 使用
/code-review审查实现 - 使用
/test-coverage验证覆盖率
相关 Agent¶
此命令会调用 tdd-guide Agent:
~/.claude/agents/tdd-guide.md
并且可以引用 tdd-workflow 技能:
~/.claude/skills/tdd-workflow/
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 ev/ECC