TDD 개발 Skill
개요
이 Skill은 작성된 테스트 시나리오를 기반으로 TDD(Test-Driven Development) 방식으로 코드를 구현합니다.
시나리오 파일의 - [ ] 체크박스를 하나씩 - [x]로 완료하며 진행합니다.
전제 조건
TDD 개발을 시작하기 전에 시나리오 파일이 먼저 작성되어 있어야 합니다.
시나리오가 없다면 tdd-scenario Skill을 먼저 사용하세요.
TDD 사이클: Red-Green-Refactor
code
┌─────────────────────────────────────────────────────────┐ │ │ │ ┌─────────┐ ┌─────────┐ ┌──────────┐ │ │ │ RED │ ───▶ │ GREEN │ ───▶ │ REFACTOR │ │ │ │ (실패) │ │ (통과) │ │ (개선) │ │ │ └─────────┘ └─────────┘ └──────────┘ │ │ │ │ │ │ └───────────────────────────────────┘ │ │ 반복 │ └─────────────────────────────────────────────────────────┘
Red (실패하는 테스트 작성)
- •시나리오를 테스트 코드로 변환
- •테스트 실행 → 실패 확인 (이것이 중요!)
- •아직 구현이 없으므로 실패해야 정상
Green (테스트 통과)
- •테스트를 통과하는 최소한의 코드 작성
- •완벽한 코드가 아니어도 됨
- •목표: 테스트 통과
Refactor (리팩토링)
- •테스트가 통과하는 상태 유지
- •코드 품질 개선
- •중복 제거, 가독성 향상
작업 순서
1. 시나리오 파일 확인
markdown
시나리오 파일을 찾아서 미완료 항목을 확인합니다. 예시: ### 테스트 - [x] 올바르게 요청하면 200 OK를 반환한다 - [ ] email이 없으면 400을 반환한다 ← 다음 작업 대상 - [ ] email 형식이 잘못되면 400을 반환한다
2. 테스트 작성 (Red)
선택한 시나리오를 테스트 코드로 변환합니다:
java
@Test
void email이_없으면_400_Bad_Request를_반환한다() {
// Arrange
var command = new CreateUserCommand(
null, // email이 없음
"username",
"password123"
);
// Act
ResponseEntity<Void> response = client.postForEntity(
"/users/signup",
command,
Void.class
);
// Assert
assertThat(response.getStatusCode().value()).isEqualTo(400);
}
3. 테스트 실행 → 실패 확인
bash
./gradlew test --tests "*클래스명*"
테스트가 실패해야 정상입니다. 실패하지 않으면:
- •이미 구현되어 있거나
- •테스트가 잘못 작성됨
4. 구현 (Green)
테스트를 통과하는 최소한의 코드를 작성합니다.
5. 테스트 실행 → 통과 확인
bash
./gradlew test --tests "*클래스명*"
6. 시나리오 체크박스 업데이트
시나리오 파일에서 완료된 항목을 체크합니다:
markdown
- [x] email이 없으면 400을 반환한다 ← [ ] → [x] 변경
7. 사용자에게 계속 진행할지 확인
중요: 하나의 테스트 케이스가 완료되면 반드시 멈추고 사용자에게 물어봅니다.
code
"✅ [시나리오명] 테스트가 완료되었습니다. 다음 시나리오로 계속 진행할까요? - 다음 시나리오: [다음 시나리오명] - 남은 시나리오: N개"
사용자가 승인하면 다음 시나리오를 진행합니다. 사용자가 중단을 원하면 현재까지의 진행 상황을 정리하고 종료합니다.
테스트 코드 작성 규칙
AAA 패턴 (Arrange-Act-Assert)
java
@Test
void 테스트_시나리오_문장() {
// Arrange (Given) - 테스트 준비
// 필요한 데이터, 객체, 상태 설정
// Act (When) - 테스트 대상 실행
// 테스트하려는 동작 수행
// Assert (Then) - 결과 검증
// 기대 결과와 실제 결과 비교
}
하나의 테스트는 하나의 시나리오
java
// 좋은 예: 하나의 검증
@Test
void email이_없으면_400을_반환한다() { ... }
@Test
void email_형식이_잘못되면_400을_반환한다() { ... }
// 나쁜 예: 여러 검증을 하나에
@Test
void email_검증() {
// null 검증
// 형식 검증
// 중복 검증
}
테스트 메서드 네이밍
시나리오 문장을 그대로 메서드명으로 사용합니다:
| 시나리오 | 메서드명 |
|---|---|
| 올바르게 요청하면 200 OK를 반환한다 | 올바르게_요청하면_200_OK를_반환한다() |
| email이 없으면 400을 반환한다 | email이_없으면_400_Bad_Request를_반환한다() |
진행 상황 추적
시나리오 파일의 체크박스로 진행 상황을 추적합니다:
markdown
### 테스트 - [x] 올바르게 요청하면 204 No Content를 반환한다 ✅ 완료 - [x] email이 없으면 400을 반환한다 ✅ 완료 - [ ] email 형식이 잘못되면 400을 반환한다 🔄 진행 중 - [ ] username이 없으면 400을 반환한다 ⏳ 대기 - [ ] password가 8자 미만이면 400을 반환한다 ⏳ 대기
주의사항
- •테스트 먼저: 구현 코드를 먼저 작성하지 않습니다
- •실패 확인: 새 테스트는 반드시 먼저 실패해야 합니다
- •최소 구현: 테스트 통과에 필요한 최소한의 코드만 작성합니다
- •작은 단위: 한 번에 하나의 시나리오만 진행합니다
- •체크박스 업데이트: 완료 즉시
[x]로 체크합니다
테스트 실행 명령어
프로젝트 타입에 따라:
bash
# Gradle (Java/Kotlin) ./gradlew test ./gradlew test --tests "*TestClassName*" # Maven (Java) mvn test mvn test -Dtest=TestClassName # npm (JavaScript/TypeScript) npm test npm test -- --grep "test name" # pytest (Python) pytest pytest -k "test_name"
관련 문서
더 자세한 내용은 다음 문서를 참조하세요:
- •cycle.md - Red-Green-Refactor 사이클 상세
- •patterns.md - 테스트 패턴 가이드
- •naming.md - 테스트 네이밍 규칙