Compose integruje się z popularnymi frameworkami testowymi.
Interoperacyjność z Espresso
W aplikacji hybrydowej komponenty Compose można znaleźć w hierarchiach widoków i widoki w elementach kompozycyjnych Compose (za pomocą elementu kompozycyjnego AndroidView).
Nie trzeba wykonywać żadnych specjalnych czynności, aby dopasować oba typy. Widoki dopasowujesz za pomocą
funkcji onView Espresso, a elementy Compose za pomocą funkcji 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 wyszukiwań w Compose do określonych widoków
Podczas migracji złożonych interfejsów użytkownika 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 zwrócić błąd „Znaleziono wiele węzłów”.
Zamiast modyfikować kod produkcyjny, aby wstrzykiwać dynamiczne tagi testowe, które pozwolą odróżnić te elementy, możesz ograniczyć test Compose bezpośrednio do określonego widoku Androida.
Użyj interfejsu API onRootWithViewInteraction w regule testu. Ta funkcja akceptuje ViewInteraction Espresso, co pozwala używać Espresso do izolowania określonego widoku kontenera i wykonywania interakcji Compose wyłącznie w tej ograniczonej hierarchii.
Interakcja z elementem listy
Jeśli musisz wejść w interakcję z elementem Compose w określonym wierszu RecyclerView, użyj Espresso, aby znaleźć ten wiersz, a następnie ogranicz do niego interakcję Compose.
Spowoduje to zignorowanie identycznych elementów Compose we wszystkich innych 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 niejednoznaczności w ViewPagerach
Gdy w pamięci znajdują się jednocześnie fragmenty z identycznymi układami Compose, możesz ograniczyć wyszukiwanie do identyfikatora widoku głównego określonego fragmentu, aby zapobiec niejednoznaczności.
@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() }
Interoperacyjność z UiAutomator
Domyślnie elementy kompozycyjne są dostępne w UiAutomator tylko za pomocą
wygodnych deskryptorów (wyświetlany tekst, opis treści itp.). Jeśli chcesz
uzyskać dostęp do dowolnego elementu kompozycyjnego, który używa Modifier.testTag, musisz włączyć
właściwość semantyczną testTagsAsResourceId dla poddrzewa danego elementu kompozycyjnego. Włączenie tego działania jest przydatne w przypadku elementów kompozycyjnych, które nie mają innego unikalnego uchwytu, np. elementów kompozycyjnych z możliwością przewijania (np. LazyColumn).
Włącz właściwość semantyczną tylko raz, wysoko w hierarchii elementów kompozycyjnych, aby zapewnić dostęp do wszystkich zagnieżdżonych elementów 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 Modifier.testTag(tag) może być dostępny za pomocą
By.res(resourceName), używając tego samego tag co 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 dotycząca testowania 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 uruchamiać lokalnie, na własnej stacji roboczej.
- Testy instrumentowane: warto też uruchamiać testy instrumentowane. Są to testy, które działają 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ą dostęp do wielu urządzeń, dlatego warto testować aplikację na urządzeniach o różnych rozmiarach ekranu.
- Espresso: chociaż Espresso jest przeznaczone do interfejsów użytkownika opartych na widokach, wiedza na jego temat może być przydatna w przypadku niektórych aspektów testowania Compose .