Kotest

업데이트:

코틀린에서 가장 많이 사용되는 테스트 프레임워크이다. 코틀린 DSL을 활용해 테스트 코드를 작성할 수 있다.

왜 Kotest?

racing-car 미션을 하는 도중 테스트 코드를 작성할 때였다. 자바에서 하던 대로 Junit, Assertion을 이용했다.

class CarTest {

    @DisplayName("자동차를 생성한다.")
    @Test
    fun `create car`() {
        //given - when
        val car = Car(CarName("jason"))

        //then
        assertThat(car.getName()).isEqualTo("jason")
        assertThat(car.position).isEqualTo(0)
    }
}

이렇게 테스트를 채워나가다 kotlin에 특화된 테스트 코드가 있지 않을까 라는 생각이 들어 찾아보다 kotest를 찾게 되었다. 코틀린이 제공하는 DSL(Domain Specific Language) 스타일의 중괄호를 활용한 코드 스타일을 테스트에도 사용할 수 있게 된다.

Kotest 사용하기

  • 먼저 gradle에 의존성을 추가한다.
dependencies {
    ...

    testImplementation("io.kotest:kotest-runner-junit5:$kotestVersion") // $kotestVersion버전에 오류가 나면 원하는 버전 명시
    testImplementation("io.kotest:kotest-assertions-core:$kotestVersion")
}
  • 인텔리제이 plugin에서 kotest를 찾아 설치한다.

Testing Styles

kotest에는 다양한 레이아웃이 있다. 이 중에 원하는 하나를 상속받아 진행한다. 코틀린만을 위해 만들어진 것도 있고, 기존 테스트 프레임워크에서 영향을 받아 만들어진 것도 있다.

공식 문서는 Testing Styles

  • Annotation Spec

나는 Junit 방식과 유사한 Annotation Spec을 사용했다.

internal class CarSpec : AnnotationSpec() { // 상속

    @Test
    fun `car 생성한다`() {
        //given - when
        val car = Car(CarName("jason"))

        //then
        car.getName() shouldBe "jason"
        car.position shouldBe 0 // or car.position.shouldBe(0)
    }
}
  • Behavior Spec

Given, When, Then을 명시적으로 간결하게 정의할 수 있다.

class CarSpec : BehaviorSpec({
    given("create") {
        val carName = CarName("jason")
        `when`("5자 이하의 이름으로 생성하면") {
            val result = Car(carName)
            then("Car 생성된다.") {
                result.getName() shouldBe "jason"
                result.position shouldBe 0
            }
        }
    }
})

이 외에도 다양한 테스트 Spec이 있으니 공식문서를 참고하여 원하는 방식을 선택하면 된다.

Kotest Assertions

Kotest에서 지원해주는 여러 Assertion들을 이용해 테스트를 작성할 수 있다. 몇 가지 표현식들을 살펴보자.

  • Multitude of Matchers
    • should
    • shouldBe
    • shouldHave
    • shouldNot
    • shouldNotBe
    • shouldNotHave

    이러한 matcher들이 매우 많이 존재한다.

    matcher는 두 가지 스타일로 사용 가능하다.

    1. 중위 함수 스타일

       car.getName() shouldBe "jason"
      
    2. 확장 함수 스타일

       car.getName().shouldBe("jason")
      
  • Inspectors
    • forExactly(k) : Collection에서 조건에 해당하는 element의 수가 k개인지
      mylist.forExactly(3) {
          it.city shouldBe "Chicago"
      }
    
    • forAtLeast(k) : Collection에서 적어도 k개 이상의 element가 조건을 만족
      val mylist= listOf("sam", "gareth", "timothy", "muhammad")
        
      mylist.forAtLeast(2) {
          it.shouldHaveMinLength(7)
      }
    
  • Exceptions
    • shouldThrow : [Exception]에 원하는 예외를 넣는다
      shouldThrow<[Exception]> {
        // code in here that you expect to throw an IllegalAccessException
      }
    
    • shouldThrowAny
      val exception = shouldThrowAny {
        // test here can throw any type of Throwable!
      }
    

이러한 것들 말고도 많은 것들이 있으니 필요할 때마다 공식 문서를 참고하면서 작성하면 될 거 같다.

정리

자바 식 테스트 코드 작성법에만 익숙해져 있다 kotest를 이용해서 여러가지 테스트 Spec을 사용해보니 좀 더 직관적이고 다양한 스타일이 있어서 다채롭게 쓸 수 있었다. 현재 미션이 간단해서 unit test만 진행했지만 @SpringBootTest와 Mockk을 이용해서 통합 테스트도 추후 진행해보려고 한다.

참고

https://techblog.woowahan.com/5825/

https://beomseok95.tistory.com/368#free-spec

태그: ,

업데이트:

댓글남기기