Android에서 테스트 더블 사용

요소 또는 요소 시스템을 테스트할 때는 개별적으로 테스트합니다. 예를 들어 ViewModel을 테스트하려면 에뮬레이터를 시작하고 UI를 실행할 필요가 없습니다. ViewModel은 Android 프레임워크에 종속되지 않기 때문입니다.

하지만 테스트 대상이 작동하려면 다른 항목에 종속될 수 있습니다. 예를 들어 ViewModel이 작동하려면 데이터 저장소를 사용해야 할 수 있습니다.

테스트 대상에 종속 항목을 제공해야 하는 경우 일반적으로 테스트 더블 (또는 테스트 객체)을 만드는 것이 좋습니다. 테스트 더블은 앱에서 구성요소처럼 보이고 작동하지만 특정 동작이나 데이터를 제공하기 위해 테스트에서 만들어진 객체입니다. 주요 이점은 테스트를 더 빠르고 간단하게 할 수 있다는 것입니다.

테스트 더블 유형

테스트 더블에는 다음과 같은 다양한 유형이 있습니다.

가짜 클래스의 '작동하는' 구현이 있지만 테스트에는 적합하지만 프로덕션에는 적합하지 않은 방식으로 구현된 테스트 더블입니다.

예: 인메모리 데이터베이스

가짜에는 모의 프레임워크가 필요하지 않으며 가볍습니다. 권장됩니다.

예시 프로그래밍된 대로 동작하고 상호작용에 관한 기대치를 갖는 테스트 더블입니다. 모의 항목의 상호작용이 정의된 요구사항과 일치하지 않으면 테스트가 실패합니다. 모의 항목은 일반적으로 이 모든 작업을 실행하기 위해 모의 프레임워크로 만들어집니다.

예: 데이터베이스의 메서드가 정확히 한 번 호출되었는지 확인합니다.

스텁 프로그래밍된 대로 작동하지만 상호작용에 대한 기대가 없는 테스트 더블입니다. 일반적으로 모의 프레임워크로 만듭니다. 편의를 위해 스텁보다 가짜가 선호됩니다.
가짜 전달되지만 사용되지 않는 테스트 더블입니다(예: 매개변수로 제공하기만 하면 되는 경우).

예: 클릭 콜백으로 전달된 빈 함수

스파이 실제 객체에 대한 래퍼로 모의 객체와 유사한 추가 정보도 추적합니다. 일반적으로 복잡성을 추가하지 않기 위해 피합니다. 따라서 스파이보다 가짜 또는 모의 테스트를 사용하는 것이 좋습니다.
그림자 Robolectric에서 사용되는 가짜입니다.

가짜 제품 사용의 예

UserRepository라는 인터페이스에 종속되고 첫 번째 사용자의 이름을 UI에 노출하는 ViewModel을 단위 테스트하려고 한다고 가정해 보겠습니다. 인터페이스를 구현하고 알려진 데이터를 반환하여 가짜 테스트 더블을 만들 수 있습니다.

object FakeUserRepository : UserRepository {
    fun getUsers() = listOf(UserAlice, UserBob)
}

val const UserAlice = User("Alice")
val const UserBob = User("Bob")

이 가짜 UserRepository는 프로덕션 버전에서 사용할 로컬 및 원격 데이터 소스에 종속되지 않습니다. 이 파일은 테스트 소스 세트에 있으며 프로덕션 앱과 함께 제공되지 않습니다.

가짜 종속 항목은 원격 데이터 소스에 의존하지 않고 알려진 데이터를 반환할 수 있습니다.
그림 1: 단위 테스트의 가짜 종속 항목

다음 테스트는 ViewModel이 첫 번째 사용자 이름을 뷰에 올바르게 노출하는지 확인합니다.

@Test
fun viewModelA_loadsUsers_showsFirstUser() {
    // Given a VM using fake data
    val viewModel = ViewModelA(FakeUserRepository) // Kicks off data load on init

    // Verify that the exposed data is correct
    assertEquals(viewModel.firstUserName, UserAlice.name)
}

ViewModel은 테스터가 만들기 때문에 단위 테스트에서 UserRepository를 가짜로 교체하는 것은 쉽습니다. 그러나 더 큰 테스트에서는 임의의 요소를 교체하기가 어려울 수 있습니다.

구성요소 교체 및 종속 항목 삽입

테스트에서 테스트 대상 시스템의 생성을 제어할 수 없는 경우 테스트 더블의 구성요소를 대체하는 작업이 더 복잡해지고 앱의 아키텍처가 테스트 가능 설계를 따라야 합니다.

대규모 엔드 투 엔드 테스트도 테스트 더블을 사용하면 유리할 수 있습니다. 예를 들어 앱의 전체 사용자 흐름을 탐색하는 계측 UI 테스트가 여기에 해당합니다. 이 경우 테스트를 밀폐형으로 만들 수 있습니다. 격리된 테스트는 인터넷에서 데이터를 가져오는 것과 같은 모든 외부 종속 항목을 피합니다. 이렇게 하면 안정성과 성능이 개선됩니다.

그림 2: 앱의 대부분을 다루고 원격 데이터를 조작하는 대규모 테스트입니다.

이러한 유연성을 수동으로 달성하도록 앱을 설계할 수도 있지만 Hilt와 같은 종속 항목 삽입 프레임워크를 사용하여 테스트 시간에 앱의 구성요소를 교체하는 것이 좋습니다. Hilt 테스트 가이드를 참고하세요.

다음 단계

테스트 전략 페이지에서는 다양한 유형의 테스트를 사용하여 생산성을 개선하는 방법을 보여줍니다.