tdd
TDD 명령어 (TDD Command)
이 명령어는 테스트 주도 개발 방법론을 강제하기 위해 tdd-guide 에이전트를 호출합니다.
이 명령어가 하는 일
- 인터페이스 스캐폴딩 - 타입/인터페이스 먼저 정의
- 테스트 먼저 생성 - 실패하는 테스트 작성 (RED)
- 최소 코드 구현 - 통과할 만큼만 작성 (GREEN)
- 리팩토링 - 테스트 통과를 유지하며 코드 개선 (REFACTOR)
- 커버리지 검증 - 80% 이상의 테스트 커버리지 보장
사용 시점
다음 경우에 /tdd를 사용하세요:
- 새로운 기능 구현 시
- 새로운 함수/컴포넌트 추가 시
- 버그 수정 시 (버그를 재현하는 테스트 먼저 작성)
- 기존 코드 리팩토링 시
- 핵심 비즈니스 로직 구축 시
작동 방식
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: Implementation
throw new Error('Not implemented')
}
2단계: 실패하는 테스트 작성 (RED)
// 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 day ago
}
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단계: 테스트 실행 - 실패 확인 (FAIL)
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
✅ 예상대로 테스트 실패함. 구현 준비 완료.
4단계: 최소 코드 구현 (GREEN)
// lib/liquidity.ts
export function calculateLiquidityScore(market: MarketData): number {
// Handle zero volume edge case
if (market.totalVolume === 0) {
return 0
}
// Calculate component scores (0-100 scale)
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)
// Recent activity bonus
const hoursSinceLastTrade = (Date.now() - market.lastTradeTime.getTime()) / (1000 * 60 * 60)
const recencyScore = Math.max(100 - (hoursSinceLastTrade * 10), 0)
// Weighted average
const score = (
volumeScore * 0.4 +
spreadScore * 0.3 +
traderScore * 0.2 +
recencyScore * 0.1
)
return Math.min(Math.max(score, 0), 100) // Clamp to 0-100
}
5단계: 테스트 실행 - 통과 확인 (PASS)
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
✅ 모든 테스트 통과!
6단계: 리팩토링 (IMPROVE)
// 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단계: 테스트 여전히 통과하는지 검증
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
✅ 리팩토링 완료, 테스트 여전히 통과함!