Compose integruje się z popularnymi platformami testowymi.
Interoperacyjność z Espresso
W aplikacji hybrydowej komponenty Compose można znaleźć w hierarchiach widoków, a widoki w komponentach Compose (za pomocą komponentu AndroidView).
Dopasowanie do żadnego z tych typów nie wymaga specjalnych czynności. Widoki dopasowujesz do onView Espresso, a elementy Compose do ComposeTestRule.
@Test
fun androidViewInteropTest() {
// Check the initial state of a TextView that depends on a Compose state.
Espresso.onView(withText("Hello Views")).check(matches(isDisplayed()))
// Click on the Compose button that changes the state.
composeTestRule.onNodeWithText("Click here").performClick()
// Check the new value.
Espresso.onView(withText("Hello Compose")).check(matches(isDisplayed()))
}
Dodawanie semantyki w zakresie widoku na potrzeby testowania interoperacyjności Compose
Ograniczanie zakresu wyszukiwań w narzędziu Compose do konkretnych widoków
Podczas przenoszenia złożonych interfejsów do Compose możesz napotkać identyczne elementy Compose zagnieżdżone w wielu tradycyjnych widokach Androida, np. w RecyclerView lub ViewPager. W takich przypadkach standardowe wyszukiwanie w Compose, np. onNodeWithText("Save"), może się nie powieść i wyświetlić błąd „Znaleziono wiele węzłów”.
Zamiast modyfikować kod produkcyjny, aby wstrzykiwać dynamiczne tagi testowe w celu odróżnienia tych elementów, możesz ograniczyć zakres testu Compose bezpośrednio do konkretnego widoku Androida.
Użyj interfejsu onRootWithViewInteraction API w regule testowej. Ta funkcja akceptuje ViewInteractionEspresso, co umożliwia używanie Espresso do izolowania określonego kontenera View i wykonywania interakcji Compose wyłącznie w ramach tej ograniczonej hierarchii.
Interakcja z elementem listy
Jeśli musisz wejść w interakcję z elementem Compose w określonym RecyclerViewwierszu, użyj Espresso, aby go znaleźć, a następnie ogranicz interakcję z Compose do tego wiersza.
Ignoruje to identyczne elementy Compose we wszystkich pozostałych wierszach.
@Test fun testComposeButtonInsideRecyclerViewItem() = runComposeUiTest { // Scroll to the desired position using Espresso Espresso.onView(withId(recyclerViewId)) .perform(RecyclerViewActions.scrollToPosition<MyViewHolder>(3)) // Define an Espresso ViewInteraction that uniquely identifies the row val rowView = Espresso.onView( allOf( withId(rootViewId), hasDescendant(withText("Item #3")) ) ) // Scope the Compose search strictly to that specific row View onRootWithViewInteraction(rowView) .onNode(hasText("Like")) .performClick() }
Rozwiązywanie problemów z niejednoznacznością w przypadku ViewPagerów
Jeśli w pamięci znajduje się jednocześnie wiele fragmentów o identycznych układach Compose, możesz ograniczyć zakres wyszukiwania do identyfikatora widoku głównego konkretnego fragmentu, aby uniknąć niejednoznaczności dopasowania.
@Test fun testComposeButtonInsideViewPagerItem() = runComposeUiTest { // Swipe to the desired page using Espresso Espresso.onView(withId(viewPagerViewId)).perform(swipeLeft()) // Identify the specific container view using Espresso val fragmentB = Espresso.onView(withId(fragmentRootViewId)) // The generic text "Save" is now unique within this view scope onRootWithViewInteraction(fragmentB) .onNode(hasText("Save")) .assertIsDisplayed() }
Współdziałanie z UiAutomator
Domyślnie elementy kompozycyjne są dostępne z UiAutomator tylko za pomocą wygodnych deskryptorów (wyświetlany tekst, opis treści itp.). Jeśli chcesz uzyskać dostęp do dowolnego komponentu, który używa Modifier.testTag, musisz włączyć właściwość semantyczną testTagsAsResourceId dla poddrzewa danego komponentu. Włączenie tego działania jest przydatne w przypadku komponentów kompozycyjnych, które nie mają innego unikalnego uchwytu, np. komponentów kompozycyjnych z możliwością przewijania (np. LazyColumn).
Włącz właściwość semantyczną tylko raz na wysokim poziomie hierarchii funkcji kompozycyjnych, aby zapewnić dostępność wszystkich zagnieżdżonych funkcji kompozycyjnych z Modifier.testTag z poziomu UiAutomator.
Scaffold(
// Enables for all composables in the hierarchy.
modifier = Modifier.semantics {
testTagsAsResourceId = true
}
){
// Modifier.testTag is accessible from UiAutomator for composables nested here.
LazyColumn(
modifier = Modifier.testTag("myLazyColumn")
){
// Content
}
}
Każdy element kompozycyjny z symbolem Modifier.testTag(tag) może być dostępny za pomocą funkcji By.res(resourceName) przy użyciu tego samego symbolu tag co symbol resourceName.
val device = UiDevice.getInstance(getInstrumentation())
val lazyColumn: UiObject2 = device.findObject(By.res("myLazyColumn"))
// Some interaction with the lazyColumn.
Dodatkowe materiały
- Testowanie aplikacji na Androida: główna strona docelowa testowania aplikacji na Androida zawiera szersze omówienie podstaw testowania i technik 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 z użyciem instrumentacji: warto też przeprowadzać testy z użyciem instrumentacji. 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 różnych rozmiarów ekranu: użytkownicy mają do dyspozycji wiele urządzeń, dlatego warto przeprowadzać testy na różnych rozmiarach ekranu.
- Espresso: chociaż Espresso jest przeznaczony do interfejsów opartych na widokach, wiedza o nim może być przydatna w przypadku niektórych aspektów testowania Compose.