Kotlin 테스팅 | JUnit, MockK, 테스트 작성법
이 글의 핵심
import org.junit.jupiter.api.Test import kotlin.test.assertEquals.
들어가며
JUnit·Kotest 등과 함께 쓰면 given/when/then 스타일을 짧게 쓰기 좋습니다. 테스트는 프로덕션 코드와 같은 멀티플랫폼 모듈에 둘 수도 있습니다.
1. JUnit 기본
프로젝트 설정
// build.gradle.kts
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:5.9.0")
testImplementation("org.jetbrains.kotlin:kotlin-test")
}
기본 테스트
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
class CalculatorTest {
@Test
fun `덧셈 테스트`() {
val result = add(2, 3)
assertEquals(5, result)
}
@Test
fun `뺄셈 테스트`() {
val result = subtract(10, 3)
assertEquals(7, result)
}
}
fun add(a: Int, b: Int) = a + b
fun subtract(a: Int, b: Int) = a - b
Assert 메서드
import kotlin.test.*
class AssertTest {
@Test
fun `다양한 Assert`() {
assertEquals(5, 2 + 3)
assertNotEquals(4, 2 + 3)
assertTrue(5 > 3)
assertFalse(5 < 3)
assertNull(null)
assertNotNull("text")
}
}
예외 테스트
import org.junit.jupiter.api.assertThrows
class ExceptionTest {
@Test
fun `0으로 나누기 예외`() {
assertThrows<ArithmeticException> {
divide(10, 0)
}
}
}
fun divide(a: Int, b: Int): Int {
if (b == 0) throw ArithmeticException("0으로 나눌 수 없음")
return a / b
}
2. MockK
프로젝트 설정
// build.gradle.kts
dependencies {
testImplementation("io.mockk:mockk:1.13.5")
}
기본 Mock
import io.mockk.*
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
interface UserRepository {
fun findById(id: String): User?
}
data class User(val id: String, val name: String)
class UserServiceTest {
@Test
fun `사용자 조회 테스트`() {
val repository = mockk<UserRepository>()
every { repository.findById("1") } returns User("1", "홍길동")
val service = UserService(repository)
val user = service.getUser("1")
assertEquals("홍길동", user.name)
verify { repository.findById("1") }
}
}
class UserService(private val repository: UserRepository) {
fun getUser(id: String): User {
return repository.findById(id)
?: throw NoSuchElementException("User not found")
}
}
Verify
@Test
fun `호출 검증`() {
val repository = mockk<UserRepository>(relaxed = true)
val service = UserService(repository)
service.getUser("1")
verify(exactly = 1) { repository.findById("1") }
verify(atLeast = 1) { repository.findById(any()) }
}
3. 테스트 라이프사이클
Before/After
import org.junit.jupiter.api.*
class LifecycleTest {
@BeforeEach
fun setup() {
println("테스트 시작 전")
}
@AfterEach
fun teardown() {
println("테스트 종료 후")
}
@Test
fun `테스트 1`() {
println("테스트 1 실행")
}
@Test
fun `테스트 2`() {
println("테스트 2 실행")
}
}
4. 실전 예제
예제: 사용자 서비스 테스트
data class User(val id: String, val name: String, val email: String)
interface UserRepository {
fun findById(id: String): User?
fun save(user: User): User
fun findAll(): List<User>
}
class UserService(private val repository: UserRepository) {
fun getUser(id: String): User {
return repository.findById(id)
?: throw NoSuchElementException("User not found")
}
fun createUser(name: String, email: String): User {
if (name.isBlank()) {
throw IllegalArgumentException("이름은 필수입니다")
}
if (!email.contains("@")) {
throw IllegalArgumentException("이메일 형식이 잘못되었습니다")
}
val user = User(
id = generateId(),
name = name,
email = email
)
return repository.save(user)
}
fun getAllUsers(): List<User> {
return repository.findAll()
}
private fun generateId() = System.currentTimeMillis().toString()
}
class UserServiceTest {
private lateinit var repository: UserRepository
private lateinit var service: UserService
@BeforeEach
fun setup() {
repository = mockk()
service = UserService(repository)
}
@Test
fun `사용자 조회 성공`() {
val expected = User("1", "홍길동", "hong@example.com")
every { repository.findById("1") } returns expected
val result = service.getUser("1")
assertEquals(expected, result)
verify { repository.findById("1") }
}
@Test
fun `사용자 조회 실패`() {
every { repository.findById("999") } returns null
assertThrows<NoSuchElementException> {
service.getUser("999")
}
}
@Test
fun `사용자 생성 성공`() {
val user = User("1", "홍길동", "hong@example.com")
every { repository.save(any()) } returns user
val result = service.createUser("홍길동", "hong@example.com")
assertEquals("홍길동", result.name)
verify { repository.save(any()) }
}
@Test
fun `이름 없이 생성 실패`() {
assertThrows<IllegalArgumentException> {
service.createUser("", "hong@example.com")
}
}
@Test
fun `잘못된 이메일로 생성 실패`() {
assertThrows<IllegalArgumentException> {
service.createUser("홍길동", "invalid-email")
}
}
@Test
fun `모든 사용자 조회`() {
val users = listOf(
User("1", "홍길동", "hong@example.com"),
User("2", "김철수", "kim@example.com")
)
every { repository.findAll() } returns users
val result = service.getAllUsers()
assertEquals(2, result.size)
verify { repository.findAll() }
}
}
정리
핵심 요약
- JUnit: 테스트 프레임워크
- MockK: Kotlin 전용 Mock 라이브러리
- every: Mock 동작 정의
- verify: 호출 검증
- assertThrows: 예외 테스트
테스트 팁
- 단위 테스트: 함수/클래스 단위로 작성
- Mock 사용: 외부 의존성 제거
- 명확한 이름: 백틱으로 한글 테스트명 사용
- Given-When-Then: 테스트 구조화
다음 단계
관련 글
- C++ Google Test | gtest 설치부터 TEST·EXPECT_EQ
- C++ Google Mock
- C++ 테스트 전략 완벽 가이드 | 단위·통합·E2E·모킹·프로덕션 패턴 [#55-7]
- C++ 크로스 플랫폼 테스트 완벽 가이드 | CI 매트릭스·Docker·엔디안·프로덕션 패턴 [실전]
- Kotlin 시작하기 | Android 공식 언어 완벽 입문
자주 묻는 질문 (FAQ)
Q. 이 내용을 실무에서 언제 쓰나요?
A. Kotlin 테스팅 import org.junit.jupiter.api.Test import kotlin.test.assertEquals. 실전 예제와 코드로 개념부터 활용까지 정리합니다. Kotlin·테스트·JUn… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.
Q. 선행으로 읽으면 좋은 글은?
A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. Kotlin 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.
Q. 더 깊이 공부하려면?
A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- Swift 함수와 클로저 | 함수 정의, 클로저, 고차 함수
- Kotlin Spring Boot | REST API 서버 만들기
- 투 포인터 | O(n²) → O(n) 최적화 기법 완벽 정리
이 글에서 다루는 키워드 (관련 검색어)
Kotlin, 테스트, JUnit, MockK 등으로 검색하시면 이 글이 도움이 됩니다.