이번에는 Kotest
를 적용하고 간단한 Repository 테스트를 작성해보았습니다.
먼저 테스트를 위해 User 패키지 내에 UserRepository 인터페이스를 생성하였습니다.
Spring Data JPA 의 JpaRepository 를 상속받아 기본적인 CRUD 기능을 제공합니다.
interface UserRepository : JpaRepository<User, Long>
원래 Java 에서는 @DisplayName
과 @Nested
등을 활용해 한글 테스트 이름을 작성하고 given, when, then 구조는 주석으로 표현하는 방식이 일반적이었습니다.
반면 Kotest
는 주석 없이도 문법 자체로 표현할 수 있도록 설계되어 있어 테스트의 의도와 시나리오가 더 명확하게 드러납니다.
또한 Kotlin 에 친화적인 테스트 DSL 을 지원하기 때문에 이번 기회에 Kotest
를 도입해보게 되었습니다.
Spring + Gradle + Kotlin 기준으로 다음과 같이 설정하였습니다:
val kotestVersion = "5.9.1"
dependencies {
testImplementation("io.kotest:kotest-runner-junit5:$kotestVersion")
testImplementation("io.kotest:kotest-assertions-core:$kotestVersion")
testImplementation("io.kotest.extensions:kotest-extensions-spring:1.3.0")
}
tasks.withType<Test>().configureEach {
useJUnitPlatform()
}
처음에는 공식문서의 Quick Start 탭을 참고해 의존성을 추가했는데 테스트 실행 시 아래와 같은 예외가 발생했습니다:
SpecInstantiationException: Could not create instance of class ... Specs must have a public zero-arg constructor.
알고 보니 @SpringBootTest 환경에서 Kotest
를 사용할 경우 kotest-extensions-spring
모듈이 필요하며 이를 통해 Spring 의 의존성 주입 기능을 Kotest
내부에서도 사용할 수 있게 됩니다.
kotest-extensions-spring
은 다음과 같은 기능을 제공합니다:
각 테스트 옆에 실행 버튼(▶) 을 표시해주는 플러그인을 설치하였습니다.
Kotest
는 여러 가지 스타일의 테스트 문법을 제공합니다:
이 중에서 저는 대중적으로 사용되는 FunSpec
을 사용하였습니다.
@SpringBootTest
class UserRepositoryTest(
val userRepository: UserRepository,
) : FunSpec({
context("User 저장") {
test("저장 성공") {
val user = User(
username = "dustle",
password = "111",
email = "111",
nickname = "111"
).also {
userRepository.save(it)
}
val result = userRepository.findById(user.id).get()
result.also {
it.username shouldBe user.username
it.password shouldBe user.password
it.email shouldBe user.email
it.nickname shouldBe user.nickname
it.id shouldNotBe null
it.createdAt shouldNotBe null
it.updatedAt shouldNotBe null
}
}
}
})
이렇게 Kotest
를 적용해보았는데 공식 문서를 참고하면서 진행하다 보니 Spring 환경에서는 별도로 Extension을 추가해야 한다는 점을 놓쳐서 설정에 시간이 더 걸렸던 것 같습니다.
https://kotest.io/docs/quickstart
https://kotest.io/docs/extensions/spring.html