Używanie podwójnej precyzji testów na Androidzie

Podczas testowania elementu lub systemu elementów robisz to w izolacji. Na przykład, aby przetestować ViewModel, nie musisz uruchamiać emulatora ani uruchamiać interfejsu użytkownika, ponieważ nie zależy on (lub nie powinien) od platformy Android.

Jednak testowany podmiot może uzależnić się od innych osób. Na przykład ViewModel może działać tylko wtedy, gdy ma dostęp do repozytorium danych.

Jeśli musisz zapewnić zależność od testowanego tematu, zwykłą praktyką jest utworzenie testowego podwójnika (lub obiektu testowego). Podwójne obiekty testowe to obiekty, które wyglądają i działają jak komponenty w aplikacji, ale są tworzone w testach, aby zapewniać określone zachowanie lub dane. Główną zaletą jest to, że testy są szybsze i prostsze.

Typy podwójnych testów

Istnieją różne typy podwójnych testów:

Nieprawdziwe dane podwójny obiekt testowy, który zawiera „działającą” implementację klasy, ale jest ona zaimplementowana w sposób odpowiedni do testów, ale nie nadaje się do użytku produkcyjnego;

Przykład: baza danych działająca w pamięci.

Fake nie wymagają frameworka do mockowania i są lekkie. Są preferowane.

Mock podwójny obiekt testowy, który zachowuje się zgodnie z programem i ma określone oczekiwania dotyczące interakcji; Testy nie przejdą, jeśli interakcje nie będą zgodne z określonymi przez Ciebie wymaganiami. Aby to osiągnąć, zwykle korzysta się z ramy do tworzenia mocków.

Przykład: sprawdź, czy metoda w bazie danych została wywołana dokładnie raz.

Stub podwójny obiekt testowy, który zachowuje się zgodnie z programem, ale nie ma oczekiwań dotyczących interakcji; Zwykle są tworzone za pomocą frameworka do symulacji. Ze względu na prostotę preferowane są fałszywe elementy zamiast elementów zastępczych.
pusty podwójna wartość testowa, która jest przekazywana, ale nie jest używana, np. gdy musisz ją podać jako parametr;

Przykład: pusta funkcja przekazana jako wywołanie zwrotne kliknięcia.

Szpiegowski Otoczka na prawdziwym obiekcie, która śledzi również niektóre dodatkowe informacje, podobnie jak mocki. Zwykle unika się ich ze względu na złożoność. Dlatego preferowane są fałszywe lub symulowane dane.
Cień Fałszywy użyty w Robolectric.

Przykład użycia fałszywego adresu

Załóżmy, że chcesz przeprowadzić test jednostkowy ViewModel, który zależy od interfejsu o nazwie UserRepository i wyświetla nazwę pierwszego użytkownika w interfejsie użytkownika. Możesz utworzyć fałszywy test podwójny, implementując interfejs i zwracając znane dane.

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

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

Ta fałszywa wersja UserRepository nie musi być zależna od lokalnych i zdalnych źródeł danych, których używa wersja produkcyjna. Plik znajduje się w testowym zestawie źródeł i nie jest dostarczany z wersją produkcyjną aplikacji.

Fałszywa zależność może zwracać znane dane bez zależności od zdalnych źródeł danych
Ilustracja 1. Fałszywa zależność w teście jednostkowym.

Ten test sprawdza, czy ViewModel prawidłowo udostępnia widokowi pierwszą nazwę użytkownika.

@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)
}

Zastąpienie obiektu UserRepository obiektem fałszywym jest łatwe w przypadku testu jednostkowego, ponieważ widok modelu jest tworzony przez testera. Jednak w większych testach zastąpienie dowolnych elementów może być trudne.

Zastępowanie komponentów i wstrzykiwanie zależności

Jeśli testy nie mają kontroli nad tworzeniem testowanych systemów, zastępowanie komponentów podwójnymi komponentami testowymi staje się bardziej skomplikowane i wymaga, aby architektura aplikacji była zgodna z modelem testowania.

Nawet w przypadku dużych kompleksowych testów warto stosować podwójne testy, np. testowanie zintegrowanego interfejsu użytkownika, które obejmuje pełny przepływ danych w aplikacji. W tym przypadku warto przeprowadzić test hermetyczny. Test hermetyczny wyklucza wszystkie zewnętrzne zależności, takie jak pobieranie danych z internetu. Dzięki temu zwiększysz niezawodność i wydajność.

Rysunek 2. Duży test obejmujący większość aplikacji i udawane dane zdalne.

Możesz zaprojektować aplikację tak, aby uzyskać tę elastyczność ręcznie, ale zalecamy użycie frameworku wstrzykiwania zależności, takiego jak Hilt, aby zastąpić komponenty w aplikacji w czasie testów. Zapoznaj się z przewodnikiem po testowaniu Hilta.

Dalsze kroki

Na stronie Strategie testowania znajdziesz informacje o tym, jak zwiększyć produktywność za pomocą różnych typów testów.