Android: Kotest 알아보기 #1

rivermoon·2025년 4월 1일
post-thumbnail

해당 아티클은 모두 공식문서를 기반으로 작성됩니다.

Introduction

Android 앱 개발을 하다 보면, 우리는 ViewModel, UseCase, Repository 등의 로직을 테스트할 일이 분명 생기기 마련이죠.
보통은 JUnit을 사용하지만, Kotlin 개발자라면 Kotest를 고려할 만합니다.
Kotest는 Kotlin에 최적화된 Testing Framework로, 훨씬 Kotlin스럽고, 직관적인 DSL을 제공한답니다.

Kotest란?

  • Kotlin 특화 테스트 프레임워크
  • 다양한 테스트 스타일 제공 (DescribeSpec, FunSpec, BehaviorSpec 등)
  • Nested Test, Dynamic Test, Property-based Test 지원
  • Kotlin DSL 기반으로 가독성 높은 테스트 코드 작성 가능

JUnit과의 비교

Kotest Android 환경 세팅

Version 관리 (version.toml)

kotestVersion = "5.9.0"
kotest-runner = { group = "io.kotest", name = "kotest-runner-junit5", version.ref = "kotestVersion" }
kotest-assertions = { group = "io.kotest", name = "kotest-assertions-core", version.ref = "kotestVersion" }
kotest-property = { group = "io.kotest", name = "kotest-property", version.ref = "kotestVersion" }

build.gradle.kts

    testImplementation(libs.kotest.runner)
    testImplementation(libs.kotest.assertions)
    testImplementation(libs.kotest.property)

의존성 추가 &

    testOptions {
        unitTests.all {
            it.useJUnitPlatform()
        }
    }

테스트 옵션을 추가한다.(요거 없으면 안돼요.)

그 후 공식문서에 있는 샘플 코드를 삽입하여 정상적으로 실행되는 지 확인 합니다.

test 패키지에 MyTests라는 class로 파일을 생성했는데 일반적인 Junit 테스트와는 다르게 옆에 실행버튼이 뜨지 않아요.

안드로이드 스튜디오 기준으로 market에서 Kotest Plugin을 설치해야만 정상적으로 실행을 할수 있음!

이렇게 정상적으로 설정을 한다면 다음과 같은 결과를 받을 수 있다!

Nested Tests

테스트 안에 또 다른 테스트를 구조적으로 넣을 수 있는 기능
→ 마치 디렉토리 안에 서브 디렉토리를 만드는 것과 똑같은 개념

💡 용어

용어설명
test container다른 테스트를 포함할 수 있는 테스트 블록
test case더 이상 하위 테스트가 없는 진짜 "단일 테스트"
class NestedTest : DescribeSpec({
    describe("an outer test") { // <- 컨테이너
        it("an inner test") { //<- 케이스
            1 + 2 shouldBe 3
        }
        it("an inner test too!") { // <- 케이스
            3 + 4 shouldBe 7
        }
    }
})

요약

  • container = 테스트를 묶는 그룹
  • case = 실제로 검증하는 테스트
  • Nesting = 이런 container를 트리처럼 만들 수 있음

Dynamic Test

테스트를 런타임에 동적으로 생성하는 기능
(컴파일 타임에 고정된 테스트 수를 넘어서, 실행할 때 자유롭게 생성 가능)

✨ 왜 필요할까?

기존 JUnit처럼

@Test fun a() {}
@Test fun b() {}
@Test fun c() {}

이렇게 각각 수동으로 써야 했다면
Kotest는 아래처럼
List, Map, Config, Property 등 반복되는 구조를 동적으로 처리 가능

listOf("sam", "pam", "tim").forEach {
    test("$it should be a three letter name") {
        it.shouldHaveLength(3)
    }
}

동작 방식

테스트가 static 하게 컴파일 타임에 정해지는 게 아니라,
테스트를 실행할 때 list나 조건에 따라 동적으로 만들어짐

📌 예제 코드 분석

class DynamicTests : FunSpec({

    listOf(
        "sam",
        "pam",
        "tim",
    ).forEach {
        test("$it should be a three letter name") {
            it.shouldHaveLength(3)
        }
    }
})

Kotest가 실행되면서 자동으로 아래처럼 해석됨!

이게 왜 좋냐?

  • 테스트 코드를 반복해서 작성할 필요 없음
  • 조건, 리스트, Map, 데이터 파일 등을 통해 테스트를 대량으로 생성 가능
  • 실전에서 파라미터화, 케이스 분류 등에 매우 유용

Lifecycle Callbacks

테스트를 실행할 때,
실행 전/후에 자동으로 수행되는 훅(Hook) 함수를 등록하는 기능
ex)
테스트 전 → 초기화
테스트 후 → 정리, 리소스 해제
컨테이너 시작 → 외부 환경 준비
Spec 전체 시작 → DB 연결, 로그 초기화 등

💡 왜 필요할까?

실전에서는 보통 테스트할 때 다음을 준비해야 함

작업예시
테스트 시작 전에 준비DB 초기화, Mock 준비, API Stub 시작
테스트 끝나고 정리DB 비우기, Mock 해제, Stub 종료
Spec 단위로 준비리소스 연결, 설정 로딩

이걸 자동으로 할 수 있는 기능이 Lifecycle Callback임

class CallBackTest : FunSpec({

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

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

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

})

▶ 실행 흐름

[beforeEach] Hello from sam should be a three letter name
[테스트] sam should be a three letter name
[afterEach] Goodbye from sam should be a three letter name

callback 재사용?

특정 작업을 여러 테스트에서 공통으로 하고 싶을 때 아래처럼 함수화 가능

val resetDatabase: BeforeTest = {
    println("DB 초기화")
}

class ReusableCallbacks : FunSpec({

    beforeTest(resetDatabase)

    test("DB가 깨끗해야하는 테스트") {
        println("테스트 실행")
    }
})

느낀점 및 마무리

Kotest는 단순한 단위 테스트를 넘어서

  • Kotlin다운 DSL
  • 구조화된 Nested Test
  • 유연한 Dynamic Test
    를 지원하여 Android 개발에 큰 장점을 가져다 준다.

JUnit에 비해 초기 러닝커브가 있을 수 있지만,
실제 적용해보면 테스트 코드가 훨씬 읽기 쉽고 관리하기 좋아질 것 같다.


이번 아티클에서는 공식문서의 Introduction ~ Writing Test을 다뤘으며, 다음 아티클은
Testing Styles, Conditional Evaluation을 다뤄볼 예정입니다.

레퍼런스

https://kotest.io/docs/framework/writing-tests.html

profile
Android Developer

0개의 댓글