ViewModel 테스트 코드 작성 방법
ViewModel 인스턴스를 생성하여 테스트하는 것은 간단해 보일 수 있지만, 생명주기 이벤트나 상태 관리와 관련된 테스트에서는 여러 가지 어려움이 있습니다. 예를 들어, onCleared()와 같은 생명주기 이벤트를 시뮬레이션하거나, 인스턴스 상태 저장 및 복원 시나리오를 테스트하거나, 구성 변경 시 상태 보존을 확인하는 데 제한이 있습니다.
---
ViewModelScenario 소개
이러한 제한을 해결하기 위해 ViewModelScenario라는 강력한 테스트 도구가 도입되었습니다. 이 도구를 사용하려면 다음과 같은 의존성을 프로젝트에 추가해야 합니다:
implementation("androidx.lifecycle:lifecycle-viewmodel-testing:2.9.0")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0")
---
테스트 환경 요구 사항
ViewModelScenario를 사용하여 ViewModel을 테스트할 때, 다음과 같은 단위 테스트를 작성할 수 있습니다:
import androidx.lifecycle.createSavedStateHandle // CreationExtras에 대한 확장 함수
class TestObjViewModelTest {
@Test
fun testStateRestoration() = runTest {
viewModelScenario {
TestObjViewModel(
scope = this@runTest,
handle = createSavedStateHandle(),
)
}.use { it: ViewModelScenario<TestObjViewModel> ->
// ViewModel 상태 설정
it.viewModel.handle[TestObjViewModel.KEY] = "John"
it.recreate()
assertEquals("John", it.viewModel.state.value)
}
}
}
여기서 createSavedStateHandle은 androidx.lifecycle 패키지에 정의된 CreationExtras에 대한 확장 함수입니다. viewModelScenario 블록은 이 확장 함수의 수신자인 CreationExtras를 제공합니다.
그러나 2025년 초 기준으로 viewmodel-testing:2.9.0을 사용하여 이 테스트를 실행하면 다음과 같은 오류가 발생할 수 있습니다:
Method containsKey in android.os.BaseBundle not mocked.
See https://developer.android.com/r/studio-ui/build/not-mocked for details.
java.lang.RuntimeException: Method containsKey in android.os.BaseBundle not mocked.
조사 결과, ViewModelScenario는 현재 SavedStateHandle, SavedStateRegistry 또는 Bundle을 사용하는 구성 요소와 함께 사용할 때 시뮬레이션된 또는 실제 Android 환경이 필요합니다. 이 요구 사항은 향후 버전에서 변경될 수 있지만, 현재로서는 다음과 같은 해결책이 있습니다.
---
해결책 1: Robolectric을 사용한 단위 테스트
단위 테스트에서 이 문제를 해결하려면 시뮬레이션된 Android 환경을 제공하는 Robolectric을 사용할 수 있습니다. 먼저, Robolectric 의존성을 추가합니다:
testImplementation("org.robolectric:robolectric:4.13")
그런 다음, 테스트 클래스에 Robolectric 테스트 러너를 지정합니다:
@RunWith(RobolectricTestRunner::class) // Bundle 작업을 위한 필수 설정
class TestObjViewModelTest {
@Test
fun testStateRestoration() = runTest {
viewModelScenario {
TestObjViewModel(
scope = this@runTest,
handle = createSavedStateHandle(),
)
}.use { it: ViewModelScenario<TestObjViewModel> ->
// ViewModel 상태 설정
it.viewModel.handle[TestObjViewModel.KEY] = "John"
it.recreate()
assertEquals("John", it.viewModel.state.value)
}
}
@Test
fun testOnCleared() = runTest {
viewModelScenario {
TestObjViewModel(
scope = this@runTest,
handle = createSavedStateHandle(),
)
}.use { it: ViewModelScenario<TestObjViewModel> ->
it.viewModel.handle[TestObjViewModel.KEY] = "John"
it.recreate()
assertFalse(it.viewModel.isSomething)
}
}
}
---
해결책 2: Instrumentation 테스트 사용
또는 테스트를 androidTest 디렉토리에 배치하고 AndroidJUnit4 러너를 사용할 수 있습니다:
@RunWith(AndroidJUnit4::class) // 실제 Android 런타임 사용
class TestObjViewModelTest {
@Test
fun testStateRestoration() = runTest {
viewModelScenario {
TestObjViewModel(
scope = this@runTest,
handle = createSavedStateHandle(),
)
}.use { it: ViewModelScenario<TestObjViewModel> ->
// ViewModel 상태 설정
it.viewModel.handle[TestObjViewModel.KEY] = "John"
it.recreate()
assertEquals("John", it.viewModel.state.value)
}
}
}
---
접근 방식 비교
Robolectric을 사용한 단위 테스트는 일반적으로 src/test/java 디렉토리에 위치하며, @RunWith(RobolectricTestRunner::class) 주석을 사용합니다. 이러한 테스트는 로컬 JVM에서 시뮬레이션된 Android 환경으로 실행되어 빠른 실행 속도를 제공합니다. 이 접근 방식은 빠른 개발 사이클과 복잡한 테스트 시나리오에 적합합니다.
Instrumentation 테스트는 src/androidTest/java 디렉토리에 위치하며, @RunWith(AndroidJUnit4::class) 주석을 사용합니다. 이러한 테스트는 실제 Android 디바이스나 에뮬레이터에서 실행되어 실제 환경에서의 앱 동작을 정확하게 검증할 수 있습니다. 실행 속도는 느리지만, Android 프레임워크에 의존하는 구성 요소를 테스트할 때 이상적입니다.
테스트 요구 사항에 따라 적절한 접근 방식을 선택하세요:
빠른 개발과 복잡한 시나리오 처리에는 Robolectric 단위 테스트가 적합합니다.
실제 디바이스에서의 동작 검증이나 Android 프레임워크 의존 구성 요소 테스트에는 Instrumentation 테스트가 적합합니다.
---
ViewModelScenario의 주요 기능
상태 복원 테스트: Android의 상태 저장 및 복원 프로세스를 시뮬레이션하여 SavedStateHandle에 저장된 데이터의 무결성을 검증할 수 있습니다.
생명주기 관리: ViewModelStore.clear()의 자동 처리와 ViewModel.onCleared() 메서드의 적절한 실행을 지원합니다. 또한, ViewModelScenario.close() 함수를 통해 수동으로 생명주기를 제어할 수 있습니다.
크로스 플랫폼 호환성: ViewModelScenario는 Kotlin Multiplatform(KMP)과 완전히 호환되어 다양한 플랫폼에서 일관된 동작을 보장합니다.
---
모범 사례
ViewModelScenario를 사용할 때는 항상 use 블록을 사용하여 리소스를 적절히 정리하고 메모리 누수를 방지하세요.
상태 보존을 위한 일반적인 시나리오와 경계 사례를 모두 테스트하여 견고성을 확보하세요.
정리 작업이 올바르게 실행되는지 확인하여 생명주기의 무결성을 유지하세요.
SavedStateHandle과의 모든 상호작용에 대한 테스트를 포함하여 데이터 처리 및 상태 복원 동작이 올바른지 확인하세요.
---
결론
ViewModelScenario는 Android ViewModel 테스트 기능을 크게 향상시킵니다. 생명주기 이벤트 및 상태 관리를 테스트하는 과정을 단순화하여 ViewModel에 대한 포괄적인 테스트를 쉽게 작성할 수 있습니다. 이 블로그에서 설명한 패턴과 모범 사례를 따르면 ViewModel이 모든 생명주기 이벤트에서 올바르게 동작하는지 확인할 수 있습니다.
적절한 테스트는 견고한 애플리케이션을 유지하는 데 필수적이며, ViewModelScenario는 이제 Android 테스트 도구 키트에서 필수적인 도구입니다.
---
태그: Android, AndroidDev, Android App Development, Programming, Software Development
출처 및 원문 링크: Testing ViewModels Lifecycle & State