Search for a command to run...
잘 작성된 테스트 코드는 리팩토링에 대한 자신감을 주고, 코드의 품질을 보장하는 안전망 역할을 합니다. 이번 챕터에서는 JUnit5와 함께 코틀린 테스트 프레임워크인 Kotest와 MockK를 사용하여 더 읽기 쉽고 코틀린스러운 테스트 코드를 작성하는 방법을 소개합니다.
BehaviorSpec, FeatureSpec 등 다양한 테스트 스펙을 제공하여 테스트의 의도를 명확하게 표현할 수 있습니다. 예를 들어, given-when-then 구조는 테스트 시나리오를 한 편의 이야기처럼 만들어줍니다.every, verify와 같은 직관적인 DSL을 제공합니다.PostService가 PostRepository를 사용하여 게시글을 생성하는 간단한 로직을 테스트한다고 가정해봅시다.
// 테스트 대상 서비스
@Service
class PostService(
private val postRepository: PostRepository
) {
fun createPost(title: String, content: String): Long {
if (title.isBlank()) {
throw IllegalArgumentException("제목은 비어있을 수 없습니다.")
}
val post = Post(title = title, content = content)
return postRepository.save(post).id
}
}
이제 MockK와 Kotest의 BehaviorSpec을 사용해 이 서비스를 테스트해 보겠습니다.
import io.kotest.core.spec.style.BehaviorSpec
import io.kotest.matchers.shouldBe
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
class PostServiceTest : BehaviorSpec({
val postRepository = mockk<PostRepository>()
val postService = PostService(postRepository)
Given("게시글 생성 요청이 주어졌을 때") {
val title = "테스트 제목"
val content = "테스트 내용"
val savedPost = Post(id = 1L, title = title, content = content)
// Mocking 설정
every { postRepository.save(any()) } returns savedPost
When("게시글 생성을 실행하면") {
val postId = postService.createPost(title, content)
Then("생성된 게시글의 ID가 반환되어야 한다") {
postId shouldBe 1L
}
Then("repository의 save 메서드가 정확히 1번 호출되어야 한다") {
verify(exactly = 1) { postRepository.save(any()) }
}
}
}
})
Given-When-Then 블록은 테스트의 전제 조건, 실행, 그리고 검증 단계를 명확하게 구분하여 코드를 이해하기 쉽게 만듭니다.mockk로 대체함으로써 외부 요인(데이터베이스 상태 등)에 영향을 받지 않는 순수한 단위 테스트가 가능해집니다.이것으로 "Kotlin과 Spring Boot로 만드는 모던 백엔드 API 서버" 시리즈를 마무리합니다. 이 시리즈가 여러분의 개발 여정에 작은 도움이 되었기를 바랍니다.