기록

[단위테스트] 테스트하기 어려운 영역 분리: 현재 시간 의존성 해결 본문

교육/강의

[단위테스트] 테스트하기 어려운 영역 분리: 현재 시간 의존성 해결

youngyin 2025. 1. 22. 00:00

1. 테스트하기 어려운 영역: 시간 의존성

소프트웨어에서 현재 시간(LocalDateTime.now())에 의존하는 코드는 테스트하기 어렵습니다. 이는 테스트 실행 시점에 따라 결과가 달라질 수 있기 때문입니다. 예를 들어:

  • 테스트가 영업 시간 내에 실행되면 성공하지만, 영업 시간 외에 실행되면 실패합니다.
  • 동일한 테스트 코드가 실행 시간에 따라 불안정한 결과를 초래합니다.

2. 문제점

아래의 기존 코드는 현재 시간에 직접적으로 의존하고 있어 테스트 실행 시마다 결과가 달라질 가능성이 있습니다:

public Order createOrder() {
    LocalDateTime now = LocalDateTime.now();
    LocalTime currentTime = now.toLocalTime();
    if (currentTime.isBefore(SHOP_OPEN_TIME) || currentTime.isAfter(SHOP_CLOSE_TIME)){
        throw new IllegalArgumentException("주문 시간이 아닙니다. 관리자에게 문의하세요.");
    }
    return new Order(LocalDateTime.now(), beverages);
}

 

문제점:
1. LocalDateTime.now() 호출 시점에 따라 결과가 달라질 수 있습니다.
2. 테스트 환경에서 현재 시간을 제어할 수 없어 영업 시간 내외의 동작을 모두 검증하기 어렵습니다.


3. 해결책: 외부에서 시간 주입

  • 기본 동작에서는 현재 시간을 그대로 사용할 수 있도록 유지합니다.
  • 테스트 시에는 외부에서 시간을 주입받아 다양한 시나리오를 검증할 수 있도록 메서드를 오버로딩합니다.
public Order createOrder() {
    return createOrder(LocalDateTime.now());
}

// 테스트를 위해 외부에서 시각을 주입받는 오버로딩 메서드
public Order createOrder(LocalDateTime now) {
    LocalTime currentTime = now.toLocalTime();
    if (currentTime.isBefore(SHOP_OPEN_TIME) || currentTime.isAfter(SHOP_CLOSE_TIME)){
        throw new IllegalArgumentException("주문 시간이 아닙니다. 관리자에게 문의하세요.");
    }
    return new Order(now, beverages);
}

4. 테스트 코드: 시간 의존성 분리 후 테스트

(1) 기본 동작 테스트

  • 현재 시간을 기반으로 주문을 생성하는 기본 동작을 검증합니다.
@Test
@DisplayName("테스트를 실행하는 시간에 따라 실패할 수도 있는 테스트")
void createOrder() {
    // Arrange
    CafeKiosk cafeKiosk = new CafeKiosk();
    Americano americano = new Americano();
    cafeKiosk.add(americano);

    // Act
    Order order = cafeKiosk.createOrder();

    // Assert
    assertThat(cafeKiosk.getBeverages()).hasSize(1); // 음료가 1개인지 확인
}

 

문제점:

  • 위 테스트는 실행 시간이 영업 시간 내에 있을 때만 성공합니다.
  • 시간이 외부에서 고정되지 않았기 때문에 불안정한 테스트입니다.

(2) 테스트 가능한 코드로 변경

  • 외부에서 고정된 시간을 주입하여 영업 시간 내 주문을 테스트합니다.
@Test
@DisplayName("Happy Case: 영업 시간 내에 주문 생성")
void createOrderWithCurrentTime() {
    // Arrange
    CafeKiosk cafeKiosk = new CafeKiosk();
    Americano americano = new Americano();
    cafeKiosk.add(americano);

    // Act
    Order order = cafeKiosk.createOrder(LocalDateTime.of(2023, 1, 17, 14, 0)); // 고정된 시간 주입

    // Assert
    assertThat(cafeKiosk.getBeverages()).hasSize(1); // 음료가 1개인지 확인
}

5. 결론: 외부 주입을 활용해 테스트 가능한 설계를 하라

테스트하기 어려운 영역(시간, 외부 시스템 등)은 외부에서 주입받는 설계를 통해 해결할 수 있습니다.

  • 외부에서 값을 주입받아 테스트 시나리오를 제어할 수 있습니다.
  • 기본 동작을 유지하면서도 다양한 시나리오에 대한 테스트를 작성할 수 있습니다.
Comments