블라디미르 코리코프 님의 "단위 테스트" 책을 정리한 포스팅입니다.
1. '단위 테스트'의 정의
- 작은 코드 조각을 대상으로, 독립적으로 빠르게 검증하는 테스트
격리성
- 독립적으로 실행 가능한 상태
- ✅ 실행 환경이나 다른 테스트에 영향받지 않음
- ✅ 순서에 의존하지 않아야 함
2. 의존성
- 내 코드가 직접 사용하지만, 내가 직접 구현하지 않은 것 (외부에 기대는 요소)
- ✅ 단위 테스트의 격리성을 보장하기 위해 실제 의존성과 함께 동작하지 않음
- ➡️ 테스트 대역으로 대체하여 핵심 로직만 집중적으로 검증
| 의존성 종류 | 설명 | 문제점 | 예시 | 해결 방법 |
| 공유 의존성 | 테스트 간에 공유되는 상태 | 테스트 간 간섭 발생 | - 정적 가변 필드 - 싱글턴 - 전역 변수 |
- 공유 제거 - 테스트마다 초기화 |
| 비공개 의존성 | 코드에 드러나지 않는 숨은 의존성 | 실패 원인 파악 어려움 | - JDBC - LocalDateTime.now() |
- 프록시 - 의존성 주입 |
| 프로세스 의존성 | 외부 프로세스에 의존하는 시스템 구성 요소 | 외부 시스템이 테스트에 영향 | - RabbitMQ - Batch |
Mock 객체 주입 |
예제) 공유 의존성
더보기
정적 가변 필드
public class SharedService {
public static int sharedCount = 0;
public void increase() {
sharedCount++;
}
}
// 테스트 A
@Test
void testA() {
SharedService service = new SharedService();
service.increase();
assertEquals(1, SharedService.sharedCount); // 통과
}
// 테스트 B (순서나 병렬 실행에 따라 실패 가능)
@Test
void testB() {
assertEquals(0, SharedService.sharedCount); // 실패할 수 있음
}
- sharedCount는 정적 변수로, 여러 테스트에서 공유됨
- 테스트 간 간섭 발생
예제) 비공개 의존성
더보기
public class TimeService {
public boolean isBusinessHour() {
LocalTime now = LocalTime.now(); // 숨겨진 의존성
return now.isAfter(LocalTime.of(9, 0)) && now.isBefore(LocalTime.of(18, 0));
}
}
// 테스트
@Test
void testBusinessHour() {
TimeService service = new TimeService();
assertTrue(service.isBusinessHour()); // 테스트 환경의 시간에 따라 결과 달라짐
}
- LocalTime.now()는 숨겨진 외부 의존성
- 재현 어려움
예제) 프로세스 의존성
더보기
public class MessageSender {
private final RabbitMQClient client;
public MessageSender(RabbitMQClient client) {
this.client = client;
}
public boolean send(String message) {
return client.sendMessage(message); // 외부 시스템 의존
}
}
// 테스트
@Test
void testSendMessage() {
MessageSender sender = new MessageSender(new RabbitMQClient("real-host"));
assertTrue(sender.send("hello")); // RabbitMQ 가동 여부에 따라 실패
}
- 테스트가 실제 외부 메시지 큐 시스템에 의존
Mock
- 테스트 대역의 한 종류
- 테스트 중인 코드가 어떤 동작을 할 수 있도록 흉내만 내는 객체
- ✅ 요청에 대해 미리 정해둔 응답 반환 (실제 동작이나 내부 상태에는 의존하지 않음)
- ✅ 메서드가 특정 횟수/순서로 호출되었는지 검증
- ➡️ 의존성으로 인해 테스트가 어려운 의존 부분을 대체
- ➡️ 의존성을 추상화해서 주입 가능해야 사용 가능
예제) Mock
더보기
Repository
@Test
public void testAdd() {
// Mock 객체 생성
ResultRepository mockRepository = Mockito.mock(ResultRepository.class);
// 테스트 대상 클래스 생성 (Mock 주입)
CalculatorService service = new CalculatorService(mockRepository);
// 테스트 실행
int result = service.add(5, 3);
// 결과 검증
assertEquals(8, result);
// Mock 객체의 동작 검증
verify(mockRepository).saveResult(8); // saveResult(8)가 호출되었는지 확인
}
'Code > Test' 카테고리의 다른 글
| [단위 테스트] 4-1. 좋은 단위 테스트의 4대 요소: 4대 요소 (0) | 2025.01.19 |
|---|---|
| [단위 테스트] 3. 단위 테스트 구조 (0) | 2025.01.07 |
| [단위 테스트] 2-2. 단위 테스트란 무엇인가: 런던파와 고전파 (1) | 2025.01.07 |
| [단위 테스트] 1-2. 단위 테스트의 목표: 커버리지 지표 (1) | 2025.01.06 |
| [단위 테스트] 1-1. 단위 테스트의 목표: 단위 테스트 목표 (0) | 2025.01.06 |