개발을 하다 보면 Repositrory 혹은 UseCase(domain 레이어를 사용할 경우)에서 로직이 정상적으로 작동하는지 시험해 보고 싶을 때 가 있을 것이다.
이와 관련하여 hilt와 TestDispatcher, mockk등을 이용하여 쉽게 테스팅 코드를 설정하는 법에 대해 알아보자
먼저 app단 gradle에 라이브러리를 추가해준다.
testImplementation ("com.google.dagger:hilt-android-testing:2.41")
// ...with Kotlin.
kaptTest ("com.google.dagger:hilt-android-compiler:2.41")
// ...with Java.
testAnnotationProcessor ("com.google.dagger:hilt-android-compiler:2.41")
// For instrumented tests.
androidTestImplementation ("com.google.dagger:hilt-android-testing:2.41")
// ...with Kotlin.
kaptAndroidTest ("com.google.dagger:hilt-android-compiler:2.41")
// ...with Java.
androidTestAnnotationProcessor( "com.google.dagger:hilt-android-compiler:2.41")
testImplementation ("org.robolectric:robolectric:4.6.1")
class MainTestRunner : AndroidJUnitRunner() {
override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
return super.newApplication(cl, HiltTestApplication::class.java.name, context)
}
}
그리고 AndroidJUnitRunner를 AndroidTest폴더에 작성해 주고 app단 gradle 해당 코드를 추가해 주면 dagger hilt test 관련 설정이 끝난다. (AndroidJUnitRunner대신 Robolectric의 @Configuration 어노테이션을 테스트하는 class위에 작성하여 이용하여는 것도 가능하다. ex)@Config(application = HiltTestApplication::class))
defaultConfig {
..
testInstrumentationRunner = "com.practice.testarchitecture.util.MainTestRunner"
}
class MainCoroutineRule(
private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher()
) : TestWatcher() {
override fun starting(description: Description) {
super.starting(description)
Dispatchers.setMain(testDispatcher)
}
override fun finished(description: Description) {
super.finished(description)
Dispatchers.resetMain()
}
}
테스트 코루틴을 사용하기 위해서 코루틴 관련 rule을 설정해 주면 된다.
@HiltAndroidTest
class TestGithubRepository {
private val coroutineRule = MainCoroutineRule()
private val hiltRule = HiltAndroidRule(this)
@get:Rule
val rule: RuleChain = RuleChain
.outerRule(hiltRule)
.around(coroutineRule)
@Inject
lateinit var searchRepositoryUseCase: SearchRepositoryUseCase
@Inject
lateinit var githubRepository: GithubRepository
@Before
fun init() {
hiltRule.inject()
}
@Test
fun test() {
runTest {
println(searchRepositoryUseCase(SearchRepositoryUseCase.Param("123")))
}
}
}
dagger2에서는 설정 방법이 좀 더 복잡하였지만 hilt에서는 위와 같이 HiltAndroidRule을 junit의 @Before 어노테이션을 이용하여 설정해 주면 된다. (스프링 junit 사용법과 같다.)
위와 같이 작업 후 실행해 주면 아래와 같은 결과를 받아 올 수 있다.
코루틴 룰을 사용하지 않고 mockk의 코틀린 전용 라이브리를 사용하여 더미 데이터로도 테스트가 가능하다.
mockk에는 coEvery, coVerify, coMatch, coAssert, coRun, coAnswers or coInvoke 같은 코루틴 suspend함수를 실행할 수 있는 함수 들이 있다.
coEvery를 이용하여 예제를 작성해 보면
@HiltAndroidTest
class TestGithubRepository {
private val coroutineRule = MainCoroutineRule()
private val hiltRule = HiltAndroidRule(this)
@get:Rule
val rule: RuleChain = RuleChain
.outerRule(hiltRule)
.around(coroutineRule)
@Inject
lateinit var searchRepositoryUseCase: SearchRepositoryUseCase
private val searchRepositoryUseCase2 : SearchRepositoryUseCase = mockk()
@Inject
lateinit var githubRepository: GithubRepository
@Before
fun init() {
hiltRule.inject()
}
@Test
fun test() {
coEvery {
searchRepositoryUseCase2(SearchRepositoryUseCase.Param("123"))
} returns Result.Success(GitHubRepositoryResponse(items = emptyList(), totalCount = 0))
runTest {
println(searchRepositoryUseCase2(SearchRepositoryUseCase.Param("123")))
println(searchRepositoryUseCase(SearchRepositoryUseCase.Param("123")))
}
}
}
출력)
System.out: Success(data=GitHubRepositoryResponse(totalCount=0, items=[]))
Success(data=GitHubRepositoryResponse(totalCount=228558, items=[ ....
이와 같이 더미 데이터를 출력할 수 있다.
runTest에서 searchRepositoryUsecase2의 Param("123")이 아닐 경우 설정한 테스트 값이 아니므로 오류가 발생한다.
자세한 사용)
출처)
https://developer.android.com/training/dependency-injection/hilt-testing?hl=ko
'안드로이드' 카테고리의 다른 글
Compose의 Stateful과 Stateless 개념 (0) | 2022.06.27 |
---|---|
Sealed Class를 이용한 Retrofit 결과 처리 (0) | 2022.06.22 |
광고 정책 위반으로 앱 삭제 대응 (0) | 2021.06.23 |
안드로이드 postValue (0) | 2021.05.29 |
viewmodel에서 R.string 처리하기 (0) | 2020.12.25 |