waveofmymind
기록하는 습관
waveofmymind
전체 방문자
오늘
어제
  • 분류 전체보기 (124)
    • 📝 정리 (5)
    • 🌊TIL (9)
    • 💻CS (1)
      • 자료구조 (1)
    • 📙Language (9)
      • ☕Java (6)
      • 🤖Kotlin (3)
    • 🍃Spring (28)
    • 👨🏻‍💻알고리즘 (67)
      • 프로그래머스 (59)
      • 백준 (3)
    • 👷DevOps (4)
      • 🐳Docker (2)
      • 🤵Jenkins (1)

블로그 메뉴

  • 홈
  • Spring
  • Java
  • 알고리즘

공지사항

인기 글

태그

  • resultset
  • 스프링 시큐리티
  • 힙
  • 스프링
  • Open AI
  • JDBC
  • til
  • SpringAOP
  • 트랜잭션 전파
  • 완전탐색
  • 챗GPT
  • mybatis
  • sql
  • kotest
  • kotlin
  • CORS
  • AOP
  • Spring Security
  • spring boot
  • chat GPT
  • Connection
  • BFS
  • 코틀린
  • 스프링 부트
  • 통합테스트
  • LeetCode
  • spring
  • 트랜잭션
  • 스택
  • 다이나믹 프로그래밍

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
waveofmymind

기록하는 습관

[Kotlin] 테스트하기 어려운 부분을 분리하기
📙Language/🤖Kotlin

[Kotlin] 테스트하기 어려운 부분을 분리하기

2023. 5. 7. 19:51

AS-IS

정해진 시간 외에는 주문을 생성할 수 없다.(10:00~22:00)

위 요구사항을 만족하는 비즈니스 로직의 코드를 다음과 같이 작성할 수 있다.

object Constants {
    val SHOP_OPEN_TIME = LocalTime.of(10, 0)
    val SHOP_CLOSE_TIME = LocalTime.of(22, 0)
}

fun createOrder(beverages: List<Beverage>): Order {
    val currentDateTime = LocalDateTime.now()
    val currentTime = currentDateTime.toLocalTime()

    if (currentTime.isBefore(Constants.SHOP_OPEN_TIME) || currentTime.isAfter(Constants.SHOP_CLOSE_TIME)) {
        throw IllegalArgumentException("주문 시간이 아닙니다. 관리자에게 문의하세요.")
    }

    return Order(currentDateTime, beverages)
}

문제 상황

위 로직을 테스트한다고 하면, 아래처럼 작성할 수 있을 것이다.

@Test
fun createOrder() {
        val cafeKiosk = CafeKiosk()
        val americano = Americano()

        cafeKiosk.add(americano)

        val order = cafeKiosk.createOrder()
        order.beverages.shouldHaveSize(1)
        order.beverages[0].name.shouldBe("아메리카노")
    }

그러나 위 테스트는 항상 성공하는 테스트일 수 없다.

currentDateTime을 LocalDateTime.now()로 생성하기 때문에, 테스트하는 시각에 따라 성공, 실패로 결과가 나눠지기 때문이다.

상수인 SHOP_OPEN_TIME을 LocalTime.of()로 바꿀 경우, 테스트 결과가 달라진다.

 

그래서 문제가 되는 createOrder 메서드를 변경해서,  LocalDateTime.now()를 외부 파라미터로 빼면, 다음과 같이 바꿀 수 있다.

fun createOrder(currentDateTime: LocalDateTime): Order {
    val currentTime = currentDateTime.toLocalTime()

    if (currentTime.isBefore(SHOP_OPEN_TIME) || currentTime.isAfter(SHOP_CLOSE_TIME)) {
        throw IllegalArgumentException("주문 시간이 아닙니다. 관리자에게 문의하세요.")
    }

    return Order(currentDateTime, beverages)
}

TO-BE

새로이 작성한 테스트의 경우, 외부 파라미터로 currentDateTime을 받도록 수정했다.

@Test
fun `createOrderOutsideOpenTime`() {
    val cafeKiosk = CafeKiosk()
    val americano = Americano()

    cafeKiosk.add(americano)

    val exception = shouldThrow<IllegalArgumentException> {
        cafeKiosk.createOrder(LocalDateTime.of(2023, 1, 17, 9, 59))
    }
    exception.message shouldBe "주문 시간이 아닙니다. 관리자에게 문의하세요."
}

외부에서 파라미터로 받도록 변경함으로써, 항상 성공하는 테스트로 만들 수 있었다.

그러나 당연스럽게도, 위는 테스트용으로 생성한 메서드이기 때문에, 검증하는데 프로덕션용 코드를 사용하지 않아도 괜찮은지에 대한 고민이 생긴다.

 

그렇지만 위 테스트는 주문을 생성하는 것을 검증하는 테스트이며, 시간에 대한 테스트가 아니다.

즉, 테스트 하고자 하는 것이 주문 생성이기 때문에 테스트하기 어려운 영역을 구분하고, 분리해서 구현해야 한다.

'📙Language > 🤖Kotlin' 카테고리의 다른 글

[PUDDY] 코틀린 Kotest로 테스트하기(w. BehaviorSpec)  (0) 2023.04.30
[Kotlin] 자바에서의 Switch, 코틀린에서의 When  (0) 2023.03.08
    '📙Language/🤖Kotlin' 카테고리의 다른 글
    • [PUDDY] 코틀린 Kotest로 테스트하기(w. BehaviorSpec)
    • [Kotlin] 자바에서의 Switch, 코틀린에서의 When
    waveofmymind
    waveofmymind

    티스토리툴바