Kotlin

Ko-Test Framework 사용해보기

dev_roach 2022. 1. 21. 14:11
728x90

코틀린 하면서 처음에는 잘 이해하지 못했던 DSL 문법의 간결함을 알게 되면서

infix 로 연계하여 만들 수 있는 DSL 구조가 좋은 것 같다는 생각이 들었다.

 

예를 들면 원래 Java + QueryDSL 을 사용한다면 아래와 같은 코드가 작성될 수 있을 것이다.

selectFrom(person).where(person.name.eq("roach))

하지만 코틀린의 infix 를 이용한다면 다르게 풀어볼 수도 있을 것이다.

selectFrom person where person.name is "roach"

내 생각엔 Kotlin 에서 QueryDSL 을 쓰는건 계속해서 JPA + QueryDSL 을 써왔기때문이라고 생각하는데

Kotlin + Spring + JPA 를 이용한다면 QueryDSL 보다 infx 를 이용한 Kotlin 스러운 DSL 로 다들 옮기고 싶어하지 않을까 싶기도 하다.

왜냐면 위에 문법만 보더라도 아래 infix 를 이용한 DSL 이 좀 더 가독성이 좋다고 생각한다.

그래서 기존의 Java 진영에서 계속해서 사용하던 테스트 프레임워크 보다

Kotlin 의 infix 를 이용해 좀 이쁘고 표현력이 좋은 라이브러리를 원했다.

 

그래서 알아보던 도중에 Ko-test 라는 프레임워크를 알게 되었다.

일단 Kotest 를 보면 아래와 같은 문법으로 작성한다 좀 더 사람이 이해하기 쉬운 문법으로 변화했다고 생각한다.

class MyTests : StringSpec({
   "length should return size of string" {
      "hello".length shouldBe 5
   }
   "startsWith should test for a prefix" {
      "world" should startWith("wor")
   }
})

일단 백문이 불여일타라고 빠르게 코드로 작성해보도록 하자.

Gradle 설정하기

Ko-Test 는 Junit Plugin 을 사용하므로 반드시 build.gradle.kt 에 아래와 같은 내용을 적어주어야 한다.

tasks.withType<Test> {
   useJUnitPlatform()
}

 

이제 dependencies 를 정의해서 다운로드 받아보자.

testImplementation("io.kotest:kotest-runner-junit5:$version")
testImplementation("io.kotest:kotest-assertions-core:$version")

그리고 나서 아래와 같은 클래스를 만들어 한번 테스트 해보자.

class MyFirstTestClass : FunSpec({
  test("my first test") {
    1 + 2 shouldBe 3
  }
})

대충 FunSpec 코드를 까보면 반드시 Unit 형태로 넘겨야 한다.

abstract class FunSpec(body: FunSpec.() -> Unit = {}) : DslDrivenSpec(), FunSpecRootScope {
   init {
      body()
   }
}

한번 테스트를 실행시켜보자.

위와 같이 테스트가 잘 동작함을 알 수 있다.

 

개인적으로 Ko-test 를 좋아하는 이유는 예전에 JavaScript 진영의 Jest 를 썼을때 Describe Spec 구조를 되게 좋아했는데, 이게 가능해서 Ko-test 를 이용한다면 이를 좀 이용해봐야 겠다는 생각이 들었다.

class NestedTestExample : DescribeSpec({

  describe("an outer test") {

    it("an inner test") {
      1 + 2 shouldBe 3
    }

    it("an inner test do") {
      3 + 4 shouldBe 7
    }

  }

})

LifeCycle Callback

우리가 기존에 사용하던 테스트 프레임워크에서는 모두 BeforeEach / AfterEach 와 같은 

Setting Up / Tear Down 기능들을 주로 제공하는데 Ko-test 에서도 역시 제공한다.

class LifeCycleCallback : FunSpec({

  beforeEach {
    println("Hello from $it")
  }

  test("sam should be a three letter name") {
    "sam".shouldHaveLength(3)
  }

  afterEach {
    println("Goodbye from $it")
  }

})

되게 마음에 드는 점은 Callback 을 별도의 Class 로 분리해서 재사용성을 높여주는 것인데

이건 약간 React 의 Hooks 느낌이 들었다.

val resetDatabase: BeforeTest = {
  println("reset database!!!")
}

class LifeCycleCallback : FunSpec({

  beforeTest(resetDatabase)

  beforeEach {
    println("Hello from $it")
  }

  test("sam should be a three letter name") {
    "sam".shouldHaveLength(3)
  }

  afterEach {
    println("Goodbye from $it")
  }

})

위처럼 BeforeTest 에 대한 부분이 계속해서 재사용이 가능한데

실제로 많은 boilerPlate 에 대한 관리를 잘 할 수 있겠다는 생각이 들었다.

 

다른 좋은 점도 더 많은데 나중에 Spring 에 적용해보면서 더 잘 적어보려고 한다.

 

'Kotlin' 카테고리의 다른 글

Kotlin DSL  (0) 2022.03.28
Kotlin 의 확장함수가 좋은 이유  (0) 2022.03.18
Kotlin 에서 Null 을 다루기  (0) 2022.01.18
[Kotlin Spring] Logger 를 간편하게  (0) 2021.12.14
[Mac] Kotlin 설치 및 CLI 에서 사용하기  (0) 2021.12.06