Skip to content

Android 계측 테스트

커스텀 Application 클래스에서 프로덕션 모듈 재정의

유닛 테스트와 달리(각 테스트 클래스에서 startKoin 또는 KoinTestExtension을 호출하여 Koin을 시작하는 방식) 계측 테스트(Instrumented tests)에서는 Koin이 Application 클래스에 의해 시작됩니다.

프로덕션 Koin 모듈을 재정의하는 경우, loadModulesunloadModules는 변경 사항이 즉시 적용되지 않기 때문에 종종 안전하지 않습니다. 대신 권장되는 접근 방식은 Application 클래스에서 startKoin이 사용하는 modules에 재정의할 module을 추가하는 것입니다. 애플리케이션의 Application을 확장하는 클래스를 그대로 유지하고 싶다면, AndroidTest 패키지 안에 다음과 같이 다른 클래스를 생성할 수 있습니다:

kotlin
class TestApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        startKoin {
            modules(productionModule, instrumentedTestModule)
        }
    }
}

계측 테스트에서 이 커스텀 Application을 사용하려면 다음과 같이 커스텀 AndroidJUnitRunner를 생성해야 할 수도 있습니다:

kotlin
class InstrumentationTestRunner : AndroidJUnitRunner() {
    override fun newApplication(
        classLoader: ClassLoader?,
        className: String?,
        context: Context?
    ): Application {
        return super.newApplication(classLoader, TestApplication::class.java.name, context)
    }
}

그런 다음 Gradle 파일에 다음과 같이 등록합니다:

groovy
testInstrumentationRunner "com.example.myapplication.InstrumentationTestRunner"

테스트 규칙을 사용하여 프로덕션 모듈 재정의

더 많은 유연성을 원한다면, 여전히 커스텀 AndroidJUnitRunner를 생성해야 하지만 커스텀 애플리케이션 내에 startKoin { ... }을 두는 대신 다음과 같이 커스텀 테스트 규칙 안에 넣을 수 있습니다:

kotlin
class KoinTestRule(
    private val modules: List<Module>
) : TestWatcher() {
    override fun starting(description: Description) {

        if (getKoinApplicationOrNull() == null) {
            startKoin {
                androidContext(InstrumentationRegistry.getInstrumentation().targetContext.applicationContext)
                modules(modules)
            }
        } else {
            loadKoinModules(modules)
        }
    }

    override fun finished(description: Description) {
        unloadKoinModules(modules)
    }
}

이러한 방식으로 다음과 같이 테스트 클래스에서 직접 정의를 재정의할 수 있습니다:

kotlin
private val instrumentedTestModule = module {
    factory<Something> { FakeSomething() }
}

@get:Rule
val koinTestRule = KoinTestRule(
    modules = listOf(productionModule, instrumentedTestModule)
)