Android와 Context 객체
Android에서 Context 객체는 God Object(신 객체)이다. Context 내에는 무수히 많은 책임과 메서드가 있다. 이 때문에 많은 개발들이 만약 context 객체가 있다면 테스트 하기 어렵다고 생각한다.
하지만 이는 틀렸다. Context 자체를 테스트 하는건 어렵지만, Context를 포함하는 객체를 테스트 하는 것은 가능하다. 아래에서 리소스를 가져오는 클래스인 ResourceRetriever 클래스를 사용해 Context를 테스트 하는 방법에 대해 살펴보도록 하자.
테스트 환경 설정
예를 들어 아래와 같은 ResourceRetriever 클래스가 있다고 해보자. 이 클래스는 안드로이드에서 리소스를 가져오는 역할을 한다.
class ResourceRetriever(private val context: Context) {
fun getString(@StringRes id: Int) : String {
return context.getString(id)
}
}
위 객체를 테스트 하기 위해서 이 글에서는 Mockito와 JUnit4를 사용한다. 따라서 build.gradle 파일에 다음 두가지 의존성을 추가하자.
dependencies {
...
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.mockito.kotlin:mockito-kotlin:4.1.0'
}
Context 테스트 하기
이제 본격적으로 Test를 시작한다. 위와 같은 ResourceRetriever을 테스트 하기 위해서는 특정 메서드를 불렸을 때 특정 응답을 주는 Stub이 필요하다.
*Stub: Test Double의 한가지 유형, 특정 메서드를 불렸을 때 특정 응답을 준다. 테스트 대상 클래스가 의존성 있는 클래스의 구현에 영향을 받는 것을 방지하기 위해 사용한다.
Context의 Mock 객체 만들기
Stub을 만들기 위해서는 먼저 Context를 Mock 객체로 만들어야 한다. Mockito를 사용해 아래와 같이 Context를 Mocking 한다.
@RunWith(MockitoJUnitRunner::class)
class AndroidContextTest {
lateinit var resourceRetriever: ResourceRetriever
@Mock
lateinit var context: Context
@Before
fun setUp() {
resourceRetriever = ResourceRetriever(context)
}
}
Context의 getString(id: Int)에 대한 Stub 만들기
여기까지 완료되었으면 getString 메서드 실행시 특정한 응답을 주도록 Stub을 만들어야 한다. getString을 호출하고 파라미터로 id가 1일 때 "test"를 반환하도록 만든다.
@Test
fun testGetString() {
val id = 1
val string = "test"
`when`(context.getString(id)).thenReturn(string)
}
이제 context.getString(1)이 불리면 "test"가 반환된다.
resourceRetriever 테스트 하기
resourceRetriever에 getString(1)을 하게 되면 context.getString(1)이 불리므로 "test"가 반환됨을 예상할 수 있다.
val result = resourceRetriever.getString(id)
따라서 result가 "test"와 같음을 Assert한다.
assertEquals(result, string)
그러면 테스트가 통과됨을 볼 수 있다.
전체 코드
전체 코드는 다음과 같다.
@RunWith(MockitoJUnitRunner::class)
class AndroidContextTest {
lateinit var resourceRetriever: ResourceRetriever
@Mock
lateinit var context: Context
@Before
fun setUp() {
resourceRetriever = ResourceRetriever(context)
}
@Test
fun testGetString() {
val id = 1
val string = "test"
`when`(context.getString(id)).thenReturn(string)
val result = resourceRetriever.getString(id)
assertEquals(result, string)
}
}
정리
이번 글에서는 안드로이드의 God Object인 Context 객체를 테스트 하는법에 대해 살펴보았다. 안드로이드에는 Context와 같은 객체가 매우 많다. 이 때문에 안드로이드에서의 테스트는 불가능한 것으로 여겨졌던 때도 있었다. 하지만, 이번 글에서도 볼 수 있듯이 Mocking Framework을 적절히 사용해 Test Double을 잘 만들어내면 이러한 객체들도 God Object들이 포함된 클래스들도 테스트가 가능해진다.