본문 바로가기
Kotlin

[Kotlin] Kotest 사용해보기

by 나는후니 2022. 5. 4.

코틀린에는 kotest라는 테스트 프레임워크가 존재합니다. 코틀린을 사용한다면 자바에서 사용하던 assertj대신 한 번쯤 kotest를 사용해보는 것도 좋다고 생각합니다.

 

간단히 java에서 사용하던 방식의 테스트를 작성하고 해당 코드를 kotest로 변경하는 과정을 소개해보겠습니다.

Quick Start

kotest는 JUnitPlatform gradle plugin을 사용합니다. 최소 4.6 버전 이상의 Gradle이 필요하기 때문에 버전을 꼭 확인해야 합니다. (최근에는 gradle 7.x 버전이 나오고 있기 때문에 새 프로젝트라면 큰 문제는 없습니다.)

// gradle + groovy
test {
  useJUnitPlatform()
}

// dependency
testImplementation 'io.kotest:kotest-runner-junit5:$version'

먼저 위 내용을 build.gradle에 추가해야 kotest를 사용하여 테스트를 진행할 수 있습니다.

assertj 전환하기

먼저 간단한 문자열 계산기를 만들고 계산기의 덧셈을 테스트하는 코드를 assertj로 작성합니다.

@DisplayName("값을 더한다.")
@Test
fun sum() {
  val result = StringCalculator.split("1,2,3").sum()
  assertThat(result).isEqualTo(6);
}

테스트 코드가 충분히 간결해보이지만, kotest를 이용하여 조금 더 직관적이고 간결하게 변경할 수 있습니다.

@DisplayName("값을 더한다.")
@Test
fun sum() {
  val result = StringCalculator.split("1,2,3").sum()
  result shouldBe 6
}

주어진 result와 결과값 other(6)이 같다면 테스트는 통과합니다. assertj를 사용할 때보다 테스트 코드의 작성이 매우 쉬워졌습니다. 또한 kotest-assertions-core 내부의 Matchers 들은 아래와 같은 형태로 사용할 수도 있습니다.

result.shouldBe(6)

이번에는 여러개의 테스트가 하나의 테스트에 존재할 때 kotest로 전환해보겠습니다.

@DisplayName("숫자를 ,로 구분하면 숫자를 나눈다")
@Test
fun split() {
  val stringCalculator = StringCalculator.split("1,2,3")
  val numbers = stringCalculator.numbers

  assertAll(
    { assertThat(stringCalculator.numbers).hasSize(3) },
    { assertThat(stringCalculator.numbers).contains(1) },
    { assertThat(stringCalculator.numbers).contains(2) },
    { assertThat(stringCalculator.numbers).contains(3) }
  )
}

자바 코드와 유사한 형태로 assertAll 내부에 assertThat여러개가 존재합니다. 이 또한 kotestSoft Assertions를 통해 해결할 수 있습니다.

@DisplayName("숫자를 ,로 구분하면 숫자를 나눈다")
@Test
fun split() {
  val stringCalculator = StringCalculator.split("1,2,3")
  val numbers = stringCalculator.numbers

  assertSoftly {
    numbers shouldHaveSize 3
    numbers shouldContain 1
    numbers shouldContain 2
    numbers shouldContain 3
  }
}

내부 assert 내용을 should~ Matcher를 이용해 해결할 수 있습니다. 하지만 더 개선의 여지가 있습니다.

@DisplayName("숫자를 ,로 구분하면 숫자를 나눈다")
@Test
fun split() {
  val stringCalculator = StringCalculator.split("1,2,3")
  val numbers = stringCalculator.numbers

  assertSoftly(numbers) {
    shouldHaveSize(3)
    shouldContain(1)
    shouldContain(2)
    shouldContain(3)
  }
}

Soft Assertions 가 이뤄질 내부에서 사용할 인스턴스를 람다를 통해 마음껏 사용할 수 있습니다. 람다를 명시적으로 사용하고 싶다면 it 키워드를 사용하면 됩니다.

assertSoftly(numbers) {
  it[0] shouldBe 1
  it[1] shouldBe 2
  it[2] shouldBe 3
}

이번에는 번호를 랜덤으로 발생시키고 해당 번호가 0 ~ 9 사이인지 테스트하는 메서드를 작성해보겠습니다.

@DisplayName("generate 시 입력한 파라미터 범위 내의 숫자를 발생한다.")
@Test
fun generateInRange() {
  val randoms = Randoms(3)
  val moveFactors = randoms.generate()

  assertAll(
    { assertThat(moveFactors[0]).isLessThan(10).isGreaterThanOrEqualTo(0) },
    { assertThat(moveFactors[1]).isLessThan(10).isGreaterThanOrEqualTo(0) },
    { assertThat(moveFactors[2]).isLessThan(10).isGreaterThanOrEqualTo(0) }
  )
}

요소 하나하나가 0보다 크거나 같고, 10보다 작은지 확인하고 있습니다. 이 코드 또한 아래와 같이 개선할 수 있습니다.

@DisplayName("generate 시 입력한 파라미터 범위 내의 숫자를 발생한다.")
@Test
fun generateInRange() {
  val randoms = Randoms(3)
  val moveFactors = randoms.generate()

  moveFactors.forAll {
    it.shouldBeBetween(0, 9)
  }
}

kotestInspector를 사용하여 collection의 내부 요소를 직접 테스트할 수 있습니다.

 

kotest를 보면 여러 다양한 테스트 방법이 존재합니다. kotlin에 관심이 있다면 한 번쯤 어떤 기술이 있는지 관심 가져볼만 하고, kotlin을 공부하고 있다면 꼭 살펴보고 직접 사용해보는 것도 좋을 것 같습니다!