Backend/테스트 코드

테스트가 어려운 영역을 분리하기

heemang_e 2024. 9. 26. 22:18

 

테스트가 어려운 코드 영역 구분

주문 메서드 작성

키오스크 주문은 10시 ~ 22시 사이로 가능하다. 그 시간 외에는 IllegalArgumentException 예외가 발생한다.

@Getter
public class CafeKiosk {

    public static final LocalTime SHOP_OPEN_TIME = LocalTime.of(10, 0);
    public static final LocalTime SHOP_CLOSE_TIME = LocalTime.of(22, 0);

    private final List<Beverage> beverages = new ArrayList<>();

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

테스트 코드 작성

아래 테스트는 통과할 수도, 통과하지 못할 수도 있다. createOrder() 메서드는 현재 시간인 currentDateTime을 사용한다. 테스트를 성공하기 위해서는 10시 ~ 22시 사이어야 하고, 그게 아니라면 테스트에 실패하게 된다.

class CafeKioskTest {
    @Test
    void createOrder() {
        CafeKiosk cafeKiosk = new CafeKiosk();
        Americano americano = new Americano();

        cafeKiosk.add(americano);

        Order order = cafeKiosk.createOrder();
        assertThat(order.getBeverages()).hasSize(1);
        assertThat(order.getBeverages().get(0).getName()).isEqualTo("아메리카노");
    }
}

 

메서드 내부에서 현재 시간을 입력받고 있기 때문에 테스트에 어려움이 있다. 테스트에 어려움이 있는 영역을 식별하였기 때문에 이를 외부로 분리하자. 외부로 분리한다는 것은 파라미터로 입력받을 수 있도록 한다는 의미다.

아래는 현재 시간을 파라미터로 입력받을 수 있도록 하였다.

@Getter
public class CafeKiosk {

    public static final LocalTime SHOP_OPEN_TIME = LocalTime.of(10, 0);
    public static final LocalTime SHOP_CLOSE_TIME = LocalTime.of(22, 0);

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

 

테스트가 어려운 부분을 외부로 분리하면서 항상 성공하는 테스트 코드를 작성할 수 있게 되었다. 또한 현재 시간을 직접 입력받기 때문에 경계값 테스트 또한 가능해졌다.

  • createOrderWithCurrentTime() : 성공 테스트 케이스
  • createOrderOutsideOpenTime() : 실패 테스트 케이스

 

결론

테스트하기 어려운 영역이 존재한다면 이를 외부로 분리할 수 없는지 생각해보자. 파라미터를 통해 직접 입력받을 수 있도록 한다면 테스트가 가능한 코드 또한 많아진다.

 

아래는 테스트를 어렵게 만드는 대표적인 예시이다.

  • 관측할 때마다 다른 값에 의존하는 코드
    • 현재 날짜/시간, 랜덤 값, 사용자 입력 …
  • 외부 세계에 영향을 주는 코드
    • 데이터베이스 기록, 메일 전송, 파일 기록 …