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żywaCountingIdlingResource
do obsługi licznika aktywnych zadań. IdlingScheduledThreadPoolExecutor
- Niestandardowa implementacja
ScheduledThreadPoolExecutor
. Ma te same funkcje i możliwości co klasaIdlingThreadPoolExecutor
, 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 implementacjamiisIdleNow()
. 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.
- Jeśli zarejestrujesz bezczynny zasób za pomocą metody z adnotacją
- 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.
Zalecane działania
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
- IdlingResourceSample: synchronizacja z zadaniami w tle.