Testy Compose są domyślnie synchronizowane z interfejsem. Gdy wywołujesz
potwierdzenie lub działanie za pomocą ComposeTestRule, test jest wcześniej synchronizowany
i czeka, aż drzewo interfejsu będzie nieaktywne.
Zwykle nie musisz podejmować żadnych działań. Istnieją jednak pewne przypadki brzegowe, o których warto wiedzieć.
Gdy test jest synchronizowany, czas w aplikacji Compose jest przyspieszany za pomocą wirtualnego zegara. Oznacza to, że testy Compose nie są przeprowadzane w czasie rzeczywistym, dzięki czemu mogą zakończyć się tak szybko, jak to możliwe.
Jeśli jednak nie używasz metod synchronizujących testy, nie nastąpi ponowne komponowanie, a interfejs będzie wyglądał na wstrzymany.
@Test
fun counterTest() {
val myCounter = mutableStateOf(0) // State that can cause recompositions.
var lastSeenValue = 0 // Used to track recompositions.
composeTestRule.setContent {
Text(myCounter.value.toString())
lastSeenValue = myCounter.value
}
myCounter.value = 1 // The state changes, but there is no recomposition.
// Fails because nothing triggered a recomposition.
assertTrue(lastSeenValue == 1)
// Passes because the assertion triggers recomposition.
composeTestRule.onNodeWithText("1").assertExists()
}Pamiętaj, że ten wymóg dotyczy tylko hierarchii Compose, a nie reszty aplikacji.
Wyłączanie automatycznej synchronizacji
Gdy wywołujesz potwierdzenie lub działanie za pomocą ComposeTestRule, np. assertExists(), test jest synchronizowany z interfejsem Compose. W niektórych przypadkach możesz chcieć zatrzymać tę synchronizację i samodzielnie sterować zegarem. Możesz na przykład sterować czasem, aby robić dokładne zrzuty ekranu animacji w momencie, gdy interfejs jest nadal zajęty. Aby wyłączyć automatyczną synchronizację, ustaw właściwość autoAdvance w mainClock na false:
composeTestRule.mainClock.autoAdvance = false
Zwykle będziesz wtedy samodzielnie przyspieszać czas. Możesz przyspieszyć czas o dokładnie 1 klatkę za pomocą advanceTimeByFrame() lub o określony czas trwania za pomocą advanceTimeBy():
composeTestRule.mainClock.advanceTimeByFrame()
composeTestRule.mainClock.advanceTimeBy(milliseconds)
Nieaktywne zasoby
Compose może synchronizować testy i interfejs, tak aby każde działanie i potwierdzenie było wykonywane w stanie nieaktywnym, w razie potrzeby czekając lub przyspieszając zegar. Niektóre operacje asynchroniczne, których wyniki wpływają na stan interfejsu, mogą być jednak wykonywane w tle, a test nie będzie o nich wiedział.
Utwórz i zarejestruj te nieaktywne zasoby w teście, aby były uwzględniane podczas określania, czy testowana aplikacja jest zajęta czy nieaktywna. Nie musisz podejmować żadnych działań, chyba że chcesz zarejestrować dodatkowe nieaktywne zasoby, np. jeśli uruchamiasz zadanie w tle, które nie jest zsynchronizowane z Espresso ani Compose.
Ten interfejs API jest bardzo podobny do nieaktywnych zasobów Espresso, które wskazują, czy
testowany obiekt jest nieaktywny czy zajęty. Aby zarejestrować
implementację IdlingResource, użyj reguły testu Compose.
composeTestRule.registerIdlingResource(idlingResource)
composeTestRule.unregisterIdlingResource(idlingResource)
Synchronizacja ręczna
W niektórych przypadkach musisz zsynchronizować interfejs Compose z innymi częściami testu lub testowanej aplikacji.
Funkcja waitForIdle() czeka, aż Compose będzie nieaktywny, ale funkcja
zależy od właściwości autoAdvance property:
composeTestRule.mainClock.autoAdvance = true // Default
composeTestRule.waitForIdle() // Advances the clock until Compose is idle.
composeTestRule.mainClock.autoAdvance = false
composeTestRule.waitForIdle() // Only waits for idling resources to become idle.
Pamiętaj, że w obu przypadkach waitForIdle() czeka też na oczekujące pomiary i rysowanie
pomiary.
Możesz też przyspieszyć zegar, aż zostanie spełniony określony warunek, za pomocą
advanceTimeUntil().
composeTestRule.mainClock.advanceTimeUntil(timeoutMs) { condition }
Pamiętaj, że dany warunek powinien sprawdzać stan, na który może wpływać ten zegar (działa tylko ze stanem Compose).
Czekanie na warunki
Każdy warunek, który zależy od pracy zewnętrznej, np. wczytywania danych lub pomiarów i rysowania w Androidzie (czyli pomiarów i rysowania poza Compose), powinien używać
bardziej ogólnej koncepcji, takiej jak waitUntil():
composeTestRule.waitUntil(timeoutMs) { condition }
Możesz też użyć dowolnego z
waitUntil pomocników:
composeTestRule.waitUntilAtLeastOneExists(matcher, timeoutMs)
composeTestRule.waitUntilDoesNotExist(matcher, timeoutMs)
composeTestRule.waitUntilExactlyOneExists(matcher, timeoutMs)
composeTestRule.waitUntilNodeCount(matcher, count, timeoutMs)
Dodatkowe materiały
- Testowanie aplikacji na Androida: główna strona docelowa testowania na Androida zawiera szersze informacje o podstawach i technikach testowania.
- Podstawy testowania: dowiedz się więcej o podstawowych koncepcjach związanych z testowaniem aplikacji na Androida.
- Testy lokalne: niektóre testy możesz przeprowadzać lokalnie, na własnej stacji roboczej.
- Testy instrumentowane: warto też przeprowadzać testy instrumentowane. Są to testy, które są przeprowadzane bezpośrednio na urządzeniu.
- Tryb ciągłej integracji: tryb ciągłej integracji umożliwia zintegrowanie testów z potokiem wdrażania.
- Testowanie na urządzeniach o różnych rozmiarach ekranu: użytkownicy mają do dyspozycji wiele urządzeń, dlatego warto testować aplikację na urządzeniach o różnych rozmiarach ekranu.
- Espresso: chociaż Espresso jest przeznaczone do interfejsów opartych na widokach, wiedza na jego temat może być przydatna w przypadku niektórych aspektów testowania Compose .