
소프트웨어에서 현재 시간(LocalDateTime.now())에 의존하는 코드는 테스트하기 어렵습니다. 이는 테스트 실행 시점에 따라 결과가 달라질 수 있기 때문입니다. 예를 들어:
아래의 기존 코드는 현재 시간에 직접적으로 의존하고 있어 테스트 실행 시마다 결과가 달라질 가능성이 있습니다:
public ParkingTicket issueTicket() {
LocalDateTime now = LocalDateTime.now();
LocalTime currentTime = now.toLocalTime();
if (currentTime.isBefore(LOT_OPEN_TIME) || currentTime.isAfter(LOT_CLOSE_TIME)){
throw new IllegalArgumentException("운영 시간이 아닙니다. 관리자에게 문의하세요.");
}
return new ParkingTicket(now, vehicle);
}
문제점:
1. LocalDateTime.now() 호출 시점에 따라 결과가 달라질 수 있습니다.
2. 테스트 환경에서 현재 시간을 제어할 수 없어 운영 시간 내외의 동작을 모두 검증하기 어렵습니다.
public ParkingTicket issueTicket() {
return issueTicket(LocalDateTime.now());
}
// 테스트를 위해 외부에서 시각을 주입받는 오버로딩 메서드
public ParkingTicket issueTicket(LocalDateTime now) {
LocalTime currentTime = now.toLocalTime();
if (currentTime.isBefore(LOT_OPEN_TIME) || currentTime.isAfter(LOT_CLOSE_TIME)){
throw new IllegalArgumentException("운영 시간이 아닙니다. 관리자에게 문의하세요.");
}
return new ParkingTicket(now, vehicle);
}
(1) 기본 동작 테스트
@Test
@DisplayName("테스트를 실행하는 시간에 따라 실패할 수도 있는 테스트")
void issueTicket() {
// Arrange
ParkingLotSystem parkingLotSystem = new ParkingLotSystem();
Vehicle vehicle = new Vehicle("XYZ-5678");
parkingLotSystem.parkVehicle(vehicle);
// Act
ParkingTicket ticket = parkingLotSystem.issueTicket();
// Assert
assertThat(ticket).isNotNull(); // 티켓이 정상적으로 발급되었는지 확인
}
문제점:
(2) 테스트 가능한 코드로 변경
@Test
@DisplayName("Happy Case: 운영 시간 내에 티켓 발급")
void issueTicketWithFixedTime() {
// Arrange
ParkingLotSystem parkingLotSystem = new ParkingLotSystem();
Vehicle vehicle = new Vehicle("XYZ-5678");
parkingLotSystem.parkVehicle(vehicle);
// Act
ParkingTicket ticket = parkingLotSystem.issueTicket(LocalDateTime.of(2023, 1, 17, 10, 0)); // 고정된 시간 주입
// Assert
assertThat(ticket).isNotNull(); // 티켓이 정상적으로 발급되었는지 확인
}
테스트하기 어려운 영역(시간, 외부 시스템 등)은 외부에서 주입받는 설계를 통해 해결할 수 있습니다.
📌 이 글은 TDD 강의를 학습한 내용을 바탕으로 재구성하였습니다. 문제가 되는 부분이 있다면 수정하겠습니다.