Zasoby nieaktywnego espresso

Zasób bezczynny reprezentuje operację asynchroniczną, której wyniki wpływają na kolejne operacje w teście interfejsu użytkownika. Rejestrując bezczynne zasoby w Espresso, możesz łatwiej weryfikować te operacje asynchroniczne podczas testowania aplikacji.

Określ, kiedy potrzebne są nieaktywne zasoby

Espresso udostępnia zaawansowane funkcje synchronizacji. Ta cecha platformy dotyczy jednak tylko operacji publikowania wiadomości w MessageQueue, np. podklasy View, która wyświetla zawartość na ekranie.

W programie Espresso nie ma informacji o żadnych innych operacjach asynchronicznych, w tym tych wykonywanych w wątku w tle, dlatego nie można zagwarantować synchronizacji w takich sytuacjach. Aby poinformować Espresso o długo trwających operacjach, musisz zarejestrować każdą z nich jako bezczynny zasób.

Jeśli nie używasz bezczynnych zasobów do testowania wyników asynchronicznej pracy w aplikacji, może się okazać, że musisz skorzystać z jednego z tych złych sposobów, aby zwiększyć niezawodność testów:

  • Dodaję połączenia do: Thread.sleep(). Jeśli dodasz sztuczne opóźnienia do testów, zakończenie testów będzie trwało dłużej. Czasami podczas wykonywania testów na wolniejszych urządzeniach nadal mogą one zakończyć się niepowodzeniem. Poza tym opóźnienia te nie są dobrze skalowane, ponieważ w kolejnych wersjach aplikacji może być konieczne wykonanie bardziej czasochłonnych zadań asynchronicznych.
  • Wdrożenie kodów ponownych prób, które wykorzystują pętlę do ciągłego sprawdzania, czy aplikacja nadal wykonuje asynchroniczną pracę do momentu przekroczenia limitu czasu. Nawet jeśli określisz w testach maksymalną liczbę ponownych prób, każde jego ponowne wykonanie zużywa zasoby systemowe, a zwłaszcza procesor.
  • Używanie instancji CountDownLatch,które umożliwiają co najmniej 1 wątkowi oczekiwanie na zakończenie określonej liczby operacji w innym wątku. Obiekty te wymagają określenia czasu oczekiwania. W przeciwnym razie aplikacja może zostać zablokowana na stałe. Zatrzaski dodatkowo zwiększają złożoność kodu, utrudniając jego obsługę.

Espresso pozwala usunąć te niestabilne obejścia z testów i zamiast tego zarejestrować asynchroniczną pracę aplikacji jako zasoby bezczynne.

Typowe przypadki użycia

Podczas wykonywania w testach operacji podobnych do podanych w przykładach poniżej rozważ użycie bezczynnego zasobu:

  • Wczytuję dane z internetu lub lokalnego źródła danych.
  • Nawiązywanie połączeń z bazami danych i wywołaniami zwrotnymi.
  • Zarządzanie usługami za pomocą usługi systemowej lub instancji IntentService.
  • wykonywanie złożonych logiki biznesowej, takich jak przekształcenia map bitowych;

Rejestrowanie bezczynnych zasobów jest szczególnie ważne, gdy te operacje aktualizują interfejs użytkownika, który następnie weryfikuje test.

Przykłady bezczynnych implementacji zasobów

Na liście poniżej znajdziesz kilka przykładów implementacji bezczynnych zasobów, które możesz zintegrować z aplikacją:

CountingIdlingResource
Licznik aktywnych zadań. Gdy licznik ma wartość 0, powiązany zasób jest uznawany za bezczynny. Ta funkcja bardzo przypomina funkcję Semaphore. W większości przypadków taka implementacja wystarcza do zarządzania asynchroniczną pracą aplikacji podczas testów.
UriIdlingResource
Podobne do CountingIdlingResource, ale przez określony czas licznik musi wynosić 0, zanim zasób zostanie uznany za bezczynny. Ten dodatkowy okres oczekiwania uwzględnia kolejne żądania sieciowe, w przypadku których aplikacja w wątku może wysłać nowe żądanie natychmiast po otrzymaniu odpowiedzi na poprzednie żądanie.
IdlingThreadPoolExecutor
Niestandardowa implementacja ThreadPoolExecutor, która śledzi łączną liczbę uruchomionych zadań w utworzonych pulach wątków. Ta klasa używa CountingIdlingResource do obsługi licznika aktywnych zadań.
IdlingScheduledThreadPoolExecutor
Niestandardowa implementacja ScheduledThreadPoolExecutor. Ma te same funkcje i możliwości co klasa IdlingThreadPoolExecutor, ale może też śledzić zadania zaplanowane na przyszłość lub zaplanowane do wykonania okresowo.

Utwórz własny zasób bezczynny

Ponieważ podczas testowania aplikacji używasz zasobów bezczynnych, może być konieczne zapewnienie niestandardowego zarządzania zasobami lub logowania. W takim przypadku sposoby opisane w poprzedniej sekcji mogą nie wystarczyć. W takim przypadku możesz rozszerzyć jedną z tych bezczynnych implementacji zasobów lub utworzyć własną.

Jeśli implementujesz własną funkcję nieaktywnego zasobu, pamiętaj o tych sprawdzonych metodach, zwłaszcza pierwszej:

Wywołuj przejścia do stanu bezczynności poza sprawdzaniem bezczynności.
Gdy aplikacja stanie się bezczynna, wywołaj onTransitionToIdle() poza implementacjami isIdleNow(). Dzięki temu Espresso nie przeprowadza drugiej, zbędnej kontroli, aby określić, czy dany zasób jest nieaktywny.

Tę rekomendację ilustruje następujący fragment kodu:

Kotlin

fun isIdle() {
    // DON'T call callback.onTransitionToIdle() here!
}

fun backgroundWorkDone() {
    // Background work finished.
    callback.onTransitionToIdle() // Good. Tells Espresso that the app is idle.

    // Don't do any post-processing work beyond this point. Espresso now
    // considers your app to be idle and moves on to the next test action.
}

Java

public void isIdle() {
    // DON'T call callback.onTransitionToIdle() here!
}

public void backgroundWorkDone() {
    // Background work finished.
    callback.onTransitionToIdle() // Good. Tells Espresso that the app is idle.

    // Don't do any post-processing work beyond this point. Espresso now
    // considers your app to be idle and moves on to the next test action.
}
Zarejestruj bezczynne zasoby, zanim będą potrzebne.

Korzyści z synchronizacji związane z bezczynnymi zasobami zaczynają obowiązywać dopiero po pierwszym wywołaniu metody isIdleNow() tego zasobu.

Poniższa lista zawiera kilka przykładów tej właściwości:

  • Jeśli zarejestrujesz bezczynny zasób za pomocą metody z adnotacją @Before, to taki zasób będzie mieć efekt w pierwszym wierszu każdego testu.
  • Jeśli zarejestrujesz bezczynny zasób w teście, ten zasób zacznie obowiązywać podczas następnego działania opartego na espresso. Dzieje się tak nawet wtedy, gdy następne działanie jest uwzględnione w tym samym teście co instrukcja rejestrująca bezczynny zasób.
Wyrejestruj bezczynne zasoby, gdy nie będą już dostępne.

Aby oszczędzać zasoby systemowe, wyrejestruj bezczynne zasoby, gdy tylko nie będą Ci już potrzebne. Jeśli na przykład zarejestrujesz bezczynny zasób za pomocą metody z adnotacją @Before, najlepiej wyrejestruj go, używając odpowiedniej metody z adnotacją @After.

Użyj rejestru nieaktywnego, aby zarejestrować i wyrejestrować nieaktywne zasoby.

Używając tego kontenera do przechowywania bezczynnych zasobów aplikacji, możesz wielokrotnie rejestrować i wyrejestrowywać bezczynne zasoby zgodnie z potrzebami, zachowując ich spójność.

Utrzymuj tylko prosty stan aplikacji w bezczynnych zasobach.

Na przykład bezczynne zasoby, które implementujesz i rejestrujesz, nie powinny zawierać odwołań do obiektów View.

Zarejestruj bezczynne zasoby

Espresso udostępnia klasę kontenera, w której możesz umieścić bezczynne zasoby aplikacji. Ta klasa o nazwie IdlingRegistry jest samodzielnym artefaktem, który w minimalnym stopniu obciąża Twoją aplikację. Umożliwia ona też podjęcie następujących działań w celu poprawy łatwości obsługi aplikacji:

  • Zamiast bezczynnych zasobów zawartych w testach aplikacji utwórz odwołanie do obiektu IdlingRegistry.
  • Zachowaj różnice w zbieraniu nieaktywnych zasobów, które są używane na potrzeby każdego wariantu kompilacji.
  • Zdefiniuj nieaktywne zasoby w usługach aplikacji, a nie w komponentach interfejsu, które się do nich odwołują.

Zintegruj nieaktywne zasoby z aplikacją

Chociaż możesz dodać bezczynne zasoby do aplikacji na kilka różnych sposobów, jedno z nich pozwala zachować herbatę dla aplikacji, jednocześnie umożliwiając określenie konkretnej operacji, którą reprezentuje dany bezczynny zasób.

Gdy dodajesz zasoby bezczynne do aplikacji, zdecydowanie zalecamy umieszczenie logiki bezczynności zasobów w samej aplikacji i wykonywanie w testach tylko operacji rejestracji i wyrejestrowania.

Chociaż używanie tego podejścia powoduje nietypową sytuację, w której używasz interfejsu tylko do testów w kodzie produkcyjnym, możesz otoczyć istniejące zasoby kodem, który już masz, zachowując rozmiar pliku APK i liczbę metod.

Alternatywne sposoby

Jeśli wolisz, by logika nieużywanych zasobów w kodzie produkcyjnym aplikacji była skuteczna, możesz zastosować kilka innych skutecznych strategii integracji:

  • Możesz tworzyć warianty kompilacji, takie jak rodzaje produktów Gradle, i używać bezczynnych zasobów tylko w kompilacji do debugowania aplikacji.
  • Użyj platformy wstrzykiwania zależności, takiej jak Dagger, aby wstawić do testów wykres zależności bezczynnych zasobów aplikacji. Jeśli używasz Daggera 2, wstrzykiwanie powinno pochodzić z podkomponentu.
  • Zaimplementuj bezczynny zasób w testach aplikacji i ujawnij tę część implementacji aplikacji, która musi być zsynchronizowana w tych testach.

    Uwaga: chociaż ta decyzja dotycząca projektu wydaje się samodzielnym odniesieniem do bezczynnych zasobów, narusza również zasadę we wszystkich aplikacjach oprócz najprostszych.

Dodatkowe materiały

Więcej informacji o używaniu Espresso w testach na Androidzie znajdziesz w tych materiałach.

Próbki