테스트 작성
제가 테스트 코드를 작성할 때 따르는 원칙과 템플릿입니다.
테스트 전략
모든 계층 테스트 (필수)
아키텍처의 모든 계층은 반드시 테스트되어야 합니다. 아래는 Controller-Service-Repository 3계층 구조의 테스트 예시입니다:
┌─────────────────────┐
│ Controller Test │ ← HTTP 요청/응답 테스트
├─────────────────────┤
│ Service Test │ ← 비즈니스 로직 테스트
├─────────────────────┤
│ Repository Test │ ← 데이터베이스 테스트
└─────────────────────┘핵심 원칙:
- Controller: HTTP 계층만 테스트, Service는 Mock
- Service: 비즈니스 로직만 테스트, Repository는 Mock
- Repository: 실제 데이터베이스 사용 (또는 TestContainer)
Given-When-Then 패턴 (필수)
모든 테스트는 Given-When-Then 주석을 포함해야 합니다:
| |
Controller 테스트
기본 템플릿
| |
Controller 테스트 체크리스트
- Service는 Mock으로 처리했는가?
- HTTP 요청/응답만 테스트하는가?
- 모든 HTTP 상태 코드를 테스트하는가? (200, 201, 400, 404 등)
- 검증 오류를 테스트하는가?
- Given-When-Then 주석이 있는가?
Service 테스트
기본 템플릿
| |
Service 테스트 체크리스트
- Repository는 Mock으로 처리했는가?
- 비즈니스 로직만 테스트하는가?
- 성공 케이스와 실패 케이스를 모두 테스트하는가?
- 예외 처리를 테스트하는가?
- verify()로 호출 여부를 검증하는가?
- Given-When-Then 주석이 있는가?
Repository 테스트
기본 템플릿
| |
Repository 테스트 체크리스트
- 실제 데이터베이스 또는 TestContainer를 사용하는가?
- @DataJpaTest 어노테이션을 사용하는가?
- @BeforeEach에서 데이터를 초기화하는가?
- 조회, 저장, 수정, 삭제를 모두 테스트하는가?
- Soft Delete 처리를 테스트하는가?
- Given-When-Then 주석이 있는가?
통합 테스트
Spring MVC 통합 테스트
| |
테스트 명명 규칙
권장 형식
| |
보안 테스트
인증/인가 테스트
모든 보안 관련 엔드포인트는 반드시 테스트되어야 합니다.
| |
SQL Injection 방지 테스트
| |
XSS 방지 테스트
| |
민감정보 보호 테스트
| |
동시성 테스트
Optimistic Locking 테스트
| |
Pessimistic Locking 테스트
| |
멀티스레드 동시성 테스트
| |
성능 테스트
N+1 쿼리 검증
| |
페이징 성능 테스트
| |
배치 처리 테스트
| |
통합 테스트 고급 패턴
트랜잭션 롤백 패턴
| |
@DirtiesContext 사용 시기
| |
TestContainers 활용
| |
데이터베이스 초기화 전략
| |
테스트 데이터 관리
Fixture 패턴
| |
테스트 격리
| |
체크리스트
모든 테스트 공통:
- Given-When-Then 주석이 명확하게 작성되었는가?
- 테스트 이름이 명확한가? (한글 권장)
- 하나의 테스트는 하나의 케이스만 검증하는가?
- 성공/실패 케이스를 모두 테스트하는가?
계층별 테스트:
- Controller 테스트: Service를 Mock으로 처리했는가?
- Service 테스트: Repository를 Mock으로 처리했는가?
- Repository 테스트: 실제 DB 또는 TestContainer를 사용하는가?
검증:
- assertThat()으로 결과를 명확히 검증하는가?
- verify()로 Mock 호출 여부를 확인하는가?
- 예외 케이스를 테스트하는가?
보안 테스트:
- 인증되지 않은 요청 테스트 (401)를 작성했는가?
- 권한 없는 접근 테스트 (403)를 작성했는가?
- SQL Injection 방지를 검증했는가?
- XSS 방지 처리를 테스트했는가?
- 민감정보가 로그/응답에 노출되지 않는지 확인했는가?
동시성 테스트:
- Optimistic Locking 테스트를 작성했는가?
- Pessimistic Locking이 필요한 경우 테스트했는가?
- 멀티스레드 환경에서 Race Condition을 검증했는가?
- 재고 감소 등 중요 비즈니스 로직의 동시성을 테스트했는가?
성능 테스트:
- N+1 쿼리 문제를 검증했는가?
- Fetch Join을 적절히 사용했는가?
- 페이징 성능을 테스트했는가?
- 배치 처리 시 flush/clear를 사용했는가?
통합 테스트:
- @Transactional로 테스트 격리를 보장했는가?
- TestContainers를 사용하여 실제 환경과 유사하게 테스트했는가?
- 테스트 순서 독립성을 보장했는가?
- @DirtiesContext를 남용하지 않았는가?
테스트 데이터 관리:
- Fixture 패턴을 사용하여 테스트 데이터를 재사용하는가?
- Builder 또는 Object Mother 패턴을 활용하는가?
- @BeforeEach와 @BeforeAll을 적절히 구분하여 사용하는가?
- 테스트 간 데이터 격리가 보장되는가?