# TDD Enforcement - 예제 및 상세 가이드

> 이 파일은 참조용이며, 자동 로딩되지 않습니다.
> 핵심 규칙은 SKILL.md를 참조하세요.

---

## RED 단계 예제

**예시 (Python - pytest):**
```python
# tests/test_user_validator.py
def test_validate_email_with_valid_address():
    """유효한 이메일 주소를 통과시켜야 한다"""
    assert validate_email("user@example.com") == True

def test_validate_email_with_invalid_address():
    """유효하지 않은 이메일 주소를 거부해야 한다"""
    assert validate_email("invalid-email") == False

def test_validate_email_with_empty_string():
    """빈 문자열을 거부해야 한다"""
    assert validate_email("") == False
```

**예시 (TypeScript - Jest):**
```typescript
// src/__tests__/userValidator.test.ts
describe('validateEmail', () => {
  it('should accept valid email addresses', () => {
    expect(validateEmail('user@example.com')).toBe(true);
  });

  it('should reject invalid email addresses', () => {
    expect(validateEmail('invalid-email')).toBe(false);
  });

  it('should reject empty strings', () => {
    expect(validateEmail('')).toBe(false);
  });
});
```

---

## GREEN 단계 예제

**예시 (Python):**
```python
# src/user_validator.py (첫 번째 반복)
def validate_email(email):
    """최소 구현: 입력받은 문자열이 @ 기호를 포함하는지 확인"""
    if not email:
        return False
    return '@' in email
```

**예시 (TypeScript):**
```typescript
// src/userValidator.ts (첫 번째 반복)
export function validateEmail(email: string): boolean {
  if (!email) return false;
  return email.includes('@');
}
```

---

## REFACTOR 단계 예제

**예시 (Python):**
```python
# src/user_validator.py (리팩터링 후)
import re

def validate_email(email):
    """RFC 5322 기본 정규표현식을 사용한 이메일 유효성 검사"""
    if not email or not isinstance(email, str):
        return False
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    return bool(re.match(pattern, email))
```

**예시 (TypeScript):**
```typescript
// src/userValidator.ts (리팩터링 후)
const EMAIL_PATTERN = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;

export function validateEmail(email: string): boolean {
  if (!email || typeof email !== 'string') {
    return false;
  }
  return EMAIL_PATTERN.test(email);
}
```

---

## TDD 워크플로우 순서 상세

```
1단계: 테스트 파일 준비
├─ 구현 대상 모듈 경로 확인
├─ 테스트 파일 생성 (규칙: 아래 참조)
└─ 테스트 파일이 빌드/실행 가능한 상태 확인

2단계: RED (실패하는 테스트 작성)
├─ 요구사항을 테스트 케이스로 작성
├─ 테스트 실행 → 반드시 실패 확인
└─ 실패 메시지가 명확한지 확인

3단계: GREEN (최소 구현)
├─ 테스트를 통과하는 코드 작성
├─ 테스트 실행 → 모두 통과 확인
└─ 구현이 과도하지 않은지 확인

4단계: REFACTOR (코드 개선)
├─ 가독성 및 성능 개선
├─ 테스트 실행 → 여전히 모두 통과 확인
└─ 새 엣지 케이스 발견 시 2단계로 돌아감

5단계: 최종 검증
├─ 모든 테스트 통과 확인
├─ 코드 커버리지 확인
└─ 커밋 및 PR 준비
```

### 각 단계에서 해야 할 것과 하지 말아야 할 것

| 단계 | 해야 할 것 | 하지 말아야 할 것 |
|------|----------|------------------|
| **RED** | • 테스트 파일 생성 • 요구사항을 테스트로 표현 • 테스트 실행 및 실패 확인 | • 구현 코드 작성 • 실패하지 않는 테스트 작성 • 테스트 실행 없이 진행 |
| **GREEN** | • 최소 구현 코드 작성 • 모든 테스트 통과 확인 • 구현의 단순성 유지 | • 과도한 최적화 • 추가 기능 구현 • 리팩터링 (REFACTOR 단계로) |
| **REFACTOR** | • 코드 품질 개선 • 테스트 유지 • 개선 후 테스트 재실행 • 새 엣지 케이스 발견 시 RED로 복귀 | • 테스트 수정 • 새 기능 추가 • 구현 로직 변경 • 테스트 없이 진행 |

---

## 경고 메커니즘 상세

### 경고 1: 테스트 파일 없이 구현 코드 작성 시

**감지 조건:**
- 새로운 함수/클래스/모듈을 생성했으나 대응하는 테스트 파일이 없는 경우
- 예: `src/userValidator.ts` 생성 후 `src/__tests__/userValidator.test.ts` 미존재

**경고 메시지:**
```
⚠️ TDD 위반 감지

작업: [새 기능 구현] Lv.2+
대상: <파일 경로>

문제: 테스트 파일 없이 구현 코드를 작성했습니다.

필수 조치:
1. 즉시 테스트 파일 생성: <권장 경로>
2. 테스트 코드를 먼저 작성하세요
3. 테스트 실행 후 실패 확인 (RED)
4. 그 다음 구현 코드를 수정하세요 (GREEN)

TDD 규칙: https://memory/specs/tdd-enforcement.md
팀장에게 보고: 이 메시지와 함께 보고됩니다.
```

### 경고 2: 실패하지 않는 테스트 작성 시

**경고 메시지:**
```
⚠️ TDD 규칙 위반

작업: [RED 단계] 테스트 작성
대상: <테스트 파일 경로>

문제: RED 단계의 테스트가 실패하지 않았습니다.

필수 조치:
1. 테스트를 다시 검토하세요
2. 테스트가 실제로 요구사항을 테스트하는가?
3. 혹은 구현이 이미 존재하는가?
4. 확인 후 재진행하세요
```

### 경고 3: 테스트 없이 리팩터링 진행 시

**경고 메시지:**
```
⚠️ TDD 위반: 테스트 없이 리팩터링

필수 조치:
1. 해당 모듈의 테스트 파일 확인: <경로>
2. 모든 테스트 실행: npm test / pytest
3. 모든 테스트 통과 확인
4. 그 후 코드 수정 진행
```

### 팀장 보고 프로세스

경고 발생 시 자동으로 팀장에게 보고된다:

```
[TDD 강제 시스템 보고]
일시: <타임스탬프>
담당자: <개발자 이름>
작업 ID: <작업 ID>
심각도: 경고

경고 유형: <경고 1/2/3>
대상 파일: <파일 경로>
설명: <경고 메시지>

상태: 경고 발생 후 개발자의 선택
- [수용] 경고 무시하고 진행 (기록됨)
- [개선] 권장 조치 따름 (기록됨)
- [이의] 팀장과 협의 (회의 일정)
```

---

## 실행 체크리스트 상세

### Pre-Implementation (구현 전)

- [ ] **작업 요구사항 확인**: 새로운 함수/클래스/모듈을 생성하는가? (Lv.2+인가?)
- [ ] **테스트 파일 경로 결정**: 테스트 파일이 들어갈 위치 확인
- [ ] **테스트 환경 확인**: pytest/Jest 등 테스트 러너가 설치되어 있는가?

### RED 단계

- [ ] **테스트 파일 생성**: 위 규칙에 따라 테스트 파일 생성
- [ ] **테스트 케이스 작성**: 정상 케이스, 엣지 케이스, 에러 케이스 각 최소 1개
- [ ] **테스트 실행**: `npm test` / `pytest` 실행
- [ ] **RED 확인**: 예상대로 실패했는가?

### GREEN 단계

- [ ] **최소 구현**: 테스트를 통과하는 최소한의 코드만 작성
- [ ] **테스트 실행**: 모든 테스트가 통과하는가?
- [ ] **GREEN 확인**: 모든 테스트가 초록색인가?

### REFACTOR 단계

- [ ] **개선 항목 식별**: 가독성, 성능, 중복 제거
- [ ] **리팩터링 실행**: 개선 사항 적용
- [ ] **테스트 재실행**: 리팩터링 후에도 모든 테스트가 통과하는가?
- [ ] **새 엣지 케이스 발견**: 있으면 RED 단계로 복귀

### Post-Implementation (구현 후)

- [ ] **최종 테스트 실행**: 전체 테스트 스위트 실행
- [ ] **코드 커버리지 확인**: 80% 이상
- [ ] **커밋 준비**: 테스트 파일과 구현 파일을 함께 커밋

---

## 금지사항 예시 코드

### 테스트 없이 새 함수 구현 (금지)

```
❌ 금지하는 패턴:
1. 새 함수를 구현 파일에 작성
2. 나중에 테스트 파일 생성
3. 테스트 코드 작성

✓ 올바른 방식:
1. 테스트 파일 생성
2. 테스트 코드 작성
3. 테스트 실행 → 실패 확인 (RED)
4. 구현 파일에 함수 작성
5. 테스트 재실행 → 통과 확인 (GREEN)
```

### 실패하지 않는 테스트 (금지)

```python
# ❌ 금지
def test_something():
    assert True  # 항상 통과

# ✓ 올바른 방식
def test_add_two_numbers():
    assert add(2, 3) == 5  # 구현이 없으면 NameError 발생 → RED
```

### 사후 테스트 패턴 (금지)

```javascript
// ❌ 금지 (Anti-pattern):
// day1: 구현 완료
function calculateTotal(items) {
  return items.reduce((sum, item) => sum + item.price, 0);
}
// day2: 나중에 테스트 추가
test('should calculate total', () => { ... });

// ✓ 올바른 방식:
// day1: 테스트 먼저
test('should calculate total', () => { ... });
// 테스트 실행 → 실패 확인
// day1 계속: 구현
function calculateTotal(items) { ... }
// 테스트 실행 → 통과 확인
```

### 테스트 건너뛰기 (금지)

```javascript
// ❌ 금지
it.skip('should validate email', () => { ... });
describe.skip('User validation', () => { ... });
// pytest.mark.skip
```

---

## 테스트 파일 네이밍 상세

### Python 프로젝트

**규칙: `test_<module>.py`** (pytest 표준)

```
구조:
src/
├── user_validator.py          # 구현 파일
└── tests/
    └── test_user_validator.py # 테스트 파일

또는 (같은 디렉토리):
src/
├── user_validator.py
└── user_validator_test.py

테스트 함수 네이밍:
- test_<함수명>_<시나리오>
- 예: test_validate_email_with_valid_address()
```

### TypeScript/JavaScript 프로젝트

**규칙: `<module>.test.ts`** (Jest 표준)

```
구조:
src/
├── userValidator.ts           # 구현 파일
└── __tests__/
    └── userValidator.test.ts  # 테스트 파일

또는 (같은 디렉토리):
src/
├── userValidator.ts
└── userValidator.test.ts

테스트 함수 네이밍:
- describe('<모듈명>', () => {
    it('<시나리오>', () => { ... });
  });
```

---

## 빠른 참조 - 테스트 명령어

**Python:**
```bash
pytest                        # 모든 테스트 실행
pytest tests/test_<module>.py # 특정 파일만 실행
pytest -v                     # 상세 출력
pytest --cov                  # 커버리지 확인
```

**TypeScript/JavaScript:**
```bash
npm test                      # 모든 테스트 실행
npm test <filename>           # 특정 파일만 실행
npm test -- --coverage        # 커버리지 확인
npm test -- --watch           # 감시 모드
```

---

## FAQ & 트러블슈팅

### Q1: 버그 수정(Lv.1)도 테스트를 먼저 작성해야 하나?
**A**: 아니오. Lv.1 버그 수정은 TDD 강제 대상이 아니다. 다만 기존 테스트가 있으면 반드시 실행하여 회귀 확인은 할 것.

### Q2: 유틸리티 함수는?
**A**: 유틸리티 함수도 "새로운 함수"이면 TDD 대상이다. 특히 재사용 목표라면 필수.

### Q3: React 컴포넌트는 어떻게 테스트하나?
**A**:
- 스냅숏 테스트 (렌더링 구조)
- 유닛 테스트 (props, state 변화)
- 통합 테스트 (사용자 상호작용, RTL)
모두 적용 가능. 프로젝트의 기존 테스트 방식을 따를 것.

### Q4: 테스트 커버리지는 몇 %여야 하나?
**A**: 최소 80% 이상. 이상적으로는 90% 이상. 하지만 테스트의 품질이 양보다 중요함.

### Q5: 기존 코드에 테스트가 없으면?
**A**:
- Lv.2 이상 기능 확장 시: 새 테스트 작성 (TDD 적용)
- Lv.1 버그 수정 시: 기존 테스트만 실행
- 대규모 리팩터링: 팀장과 협의

### Q6: 경고를 무시하면?
**A**: 경고는 팀장에게 자동 보고된다. 무시한 횟수와 사유도 기록된다. 이후 성과 평가에 반영될 수 있다.

### Q7: TDD로 인한 개발 시간 증가가 우려되는데?
**A**: 초기 학습 기간(1-2주)에는 시간이 증가할 수 있지만, 이후 버그 수정 시간과 디버깅 시간이 급감하여 전체 개발 시간이 감소한다.

### Q8: 판단 기준 테이블

| 질문 | 예 | 아니오 |
|------|----|----|
| 새로운 파일을 생성하는가? | TDD 적용 | TDD 미적용 |
| 기존 파일에 새 함수를 추가하는가? | TDD 적용 | TDD 미적용 |
| 클래스에 새 메서드를 추가하는가? | TDD 적용 (복잡한 경우) | TDD 미적용 (단순 getter/setter) |
| 기존 함수의 로직을 변경하는가? | TDD 미적용 (기존 테스트로 충분) | — |
| 테스트되지 않은 코드를 작성하는가? | TDD 적용 | TDD 미적용 |
