배경
Android TestCode 작성하기 5탄입니다. Kotlin Flow 테스트와 코루틴 테스트를 통해 비동기 테스트를 어떻게 하는지 알아봤습니다.
이번 글에서는 많은 개발자 분들이 사용하시는 Hilt에 대해서 정리하려고 합니다.
Hilt Test 하기에 앞서 공식 홈페이지를 참고해서 적절한 dependency를 추가해주세요
단위 테스트
생성자 삽입을 사용하는 클래스를 테스트할 때 이 클래스를 인스턴스화하는 데 Hilt를 사용할 필요가 없기 때문에 단위 테스트에는 Hilt가 필요하지 않습니다. 대신 생성자에 주석이 지정되지 않은 경우와 마찬가지로 Fake 종속 항목을 전달하여 클래스 생성자를 직접 호출할 수 있습니다.
@ActivityScoped
class AnalyticsAdapter @Inject constructor(
private val service: AnalyticsService
) { ... }
class AnalyticsAdapterTest {
@Test
fun `Happy path`() {
// You don't need Hilt to create an instance of AnalyticsAdapter.
// You can pass a fake or mock AnalyticsService.
val adapter = AnalyticsAdapter(fakeAnalyticsService)
assertEquals(...)
}
}
UI 테스트 설정
@HiltAndroidTest와 함께 Hilt를 사용하는 UI테스트에 주석을 지정해야 합니다. 이 주석은 각 테스트에 관한 Hilt 구성요소 생성을 담당합니다. 또한 테스트 클래스에 HiltAndroidRule을 추가해야 합니다. HiltAndroidRule은 구성요소의 상태를 관리하고, 테스트에서 삽입을 실행하는 데 사용됩니다.
@HiltAndroidTest
class SettingsActivityTest {
@get:Rule
var hiltRule = HiltAndroidRule(this)
// UI tests here.
}
테스트 애플리케이션
테스트는 Hilt가 자동으로 생성하는 Application 클래스에 관해 알아야 합니다.
Hilt를 지원하는 Application 객체에서 Hilt를 사용하는 instrumented test를 실행해야 합니다. 라이브러리는 테스트에 사용할 HiltTestApplication을 제공합니다.
Instrumented Test에서 테스트 애플리케이션 설정
Instrumented Test에서 Hilt 테스트 애플리케이션을 사용하려면 새 test runner를 구성해야 합니다.
1. androidTest 폴더에서 AndroidJUnitRunner를 확장하는 맞춤 클래스를 생성합니다.
2. newApplication 함수를 재정의하고 생성된 Hilt 테스트 애플리케이션의 이름을 전달합니다.
// A custom runner to set up the instrumented application class for tests.
class CustomTestRunner : AndroidJUnitRunner() {
override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
return super.newApplication(cl, HiltTestApplication::class.java.name, context)
}
}
그런 다음, 계측 단위 테스트 가이드에 설명된 대로 Gradle 파일에서 이 테스트 실행기를 구성합니다. 다음과 같이 전체 클래스 경로를 사용해야 합니다.
android {
defaultConfig {
// Replace com.example.android.dagger with your class path.
testInstrumentationRunner "com.example.android.dagger.CustomTestRunner"
}
}
Robolectric 테스트에서 테스트 애플리케이션 설정
Robolectric을 사용하여 UI 레이어를 테스트한다면 다음과 같이 robolectric.properties 파일에서 사용할 애플리케이션을 지정할 수 있습니다.
또는 다음과 같이 Robolectric의 @Config 주석을 사용하여 각 테스트에 애플리케이션을 개별적으로 구성할 수 있습니다.
@HiltAndroidTest
@Config(application = HiltTestApplication::class)
class SettingsActivityTest {
@get:Rule
var hiltRule = HiltAndroidRule(this)
// Robolectric tests here.
}
Android Gradle 플러그인 4.2 미만 버전을 사용하는 경우 모듈의 build.gradle 파일에 다음 구성을 적용하여 로컬 단위 테스트에서 @AndroidEntryPoint 클래스 변환을 사용 설정합니다.
hilt {
enableTransformForLocalTests = true
}
테스트에 유형 삽입
유형을 테스트에 삽입하려면 필드 삽입에 @Inject를 사용합니다. Hilt에 @Inject 필드를 채우도록 알리려면 hiltRule.inject()를 호출
@HiltAndroidTest
class SettingsActivityTest {
@get:Rule
var hiltRule = HiltAndroidRule(this)
@Inject
lateinit var analyticsAdapter: AnalyticsAdapter
@Before
fun init() {
hiltRule.inject()
}
}
결합 대체
종속 항목의 가짜 또는 모의 인스턴스를 삽입해야 한다면 프로덕션 코드에서 사용한 결합을 사용하지 말고 대신 다른 결합을 사용하도록 Hilt에 알려야 합니다. 결합을 대체하려면 결합이 포함된 모듈을, 테스트에 사용하려는 결합이 포함된 테스트 모듈로 대체해야 합니다.
// 기존 모듈
@Module
@InstallIn(SingletonComponent::class)
abstract class AnalyticsModule {
@Singleton
@Binds
abstract fun bindAnalyticsService(
analyticsServiceImpl: AnalyticsServiceImpl
): AnalyticsService
}
// 테스트용 모듈
@Module
@TestInstallIn(
components = [SingletonComponent::class],
replaces = [AnalyticsModule::class]
)
abstract class FakeAnalyticsModule {
@Singleton
@Binds
abstract fun bindAnalyticsService(
fakeAnalyticsService: FakeAnalyticsService
): AnalyticsService
}
단일 테스트에서 결합 교체
모든 테스트 대신 단일 테스트에서 결합을 바꾸려면 @UninstallModules 주석을 사용하여 테스트에서 Hilt 모듈을 제거하고 테스트 내에 새 테스트 모듈을 만듭니다.
이전 버전의 AnalyticsService 예에 따라 먼저 테스트 클래스의 @UninstallModules 주석을 사용하여 프로덕션 모듈을 무시하도록 Hilt에 지시합니다.
@UninstallModules(AnalyticsModule::class)
@HiltAndroidTest
class SettingsActivityTest {
@Module
@InstallIn(SingletonComponent::class)
abstract class TestModule {
@Singleton
@Binds
abstract fun bindAnalyticsService(
fakeAnalyticsService: FakeAnalyticsService
): AnalyticsService
}
...
}
새 값 결합
@BindValue 주석을 사용하면 테스트의 필드를 Hilt 종속 항목 그래프에 쉽게 결합할 수 있습니다. 필드에 @BindValue로 주석을 지정하면 이 필드에 대해 존재하는 한정자와 함께 선언된 필드 유형 아래에서 결합됩니다.
AnalyticsService 예에서 다음과 같이 @BindValue를 사용하여 AnalyticsService를 가짜로 대체할 수 있습니다.
@UninstallModules(AnalyticsModule::class)
@HiltAndroidTest
class SettingsActivityTest {
@BindValue @JvmField
val analyticsService: AnalyticsService = FakeAnalyticsService()
...
}
이렇게 하면 결합을 대체하고 테스트에서 결합을 참조하는 작업이 동시에 가능하므로 두 작업을 간단하게 실행할 수 있습니다.
@BindValue는 한정자 및 기타 테스트 주석과 함께 작동합니다. 예를 들어 Mockito와 같은 테스트 라이브러리를 사용한다면 다음과 같이 Robolectric 테스트에서 사용할 수 있습니다.
...
class SettingsActivityTest {
...
@BindValue @ExampleQualifier @Mock
lateinit var qualifiedVariable: ExampleCustomType
// Robolectric tests here
}
다중 결합을 추가해야 하면 @BindValue 대신 @BindValueIntoSet 및 @BindValueIntoMap 주석을 사용할 수 있습니다. 또한 @BindValueIntoMap에서는 맵 키 주석으로 필드에 주석을 지정해야 합니다.
'Android' 카테고리의 다른 글
[Android-Test] Android Compose Test 도입하기 - 실전 (0) | 2023.09.27 |
---|---|
[Android-Test] Android Compose Test 도입하기 - 이론 (0) | 2023.09.26 |
[Android-Test] Android Test코드 작성하기4 - Flow (0) | 2023.09.26 |
[Android-Test] Android Test코드 작성하기3 - Coroutines (0) | 2023.09.25 |
[Android-Test] Android Test코드 작성하기2 - Espresso (0) | 2023.09.25 |
댓글