Espresso oferuje mechanizmy, które umożliwiają przewinięcie listy lub wykonanie na niej działania w dwóch typy list: widoki adapterów i użytkowników funkcji recyklingu.
Gdy masz do czynienia z listami, zwłaszcza tymi utworzonymi za pomocą tagów RecyclerView lub
AdapterView obiekt, który Cię interesuje, może być nawet
ponieważ widoczna jest tylko niewielka liczba dzieci.
poddawany recyklingowi podczas przewijania. W tym przypadku nie można użyć metody scrollTo()
ponieważ wymaga istniejącego widoku.
Interakcja z elementami listy widoku adaptera
Zamiast używać metody onView(), rozpocznij wyszukiwanie od metody onData() i
i dopasowujesz dane powiązane z widokiem, który chcesz dopasować.
Espresso wyszuka wiersz w obiekcie Adapter i
w widocznym obszarze.
Dopasowanie danych za pomocą dopasowania widoku niestandardowego
Poniższa aktywność zawiera pole ListView, które jest oparte na: SimpleAdapter
z danymi każdego wiersza w obiekcie Map<String, Object>.

Każda mapa zawiera 2 wpisy: klucz "STR" zawierający ciąg, taki jak
"item: x" oraz klucz "LEN" zawierający Integer, który reprezentuje
ich długość. Na przykład:
{"STR" : "item: 0", "LEN": 7}
Kod kliknięcia w wierszu z „item: 50”. wygląda tak:
Kotlin
onData(allOf(`is`(instanceOf(Map::class.java)), hasEntry(equalTo("STR"), `is`("item: 50")))).perform(click())
Java
onData(allOf(is(instanceOf(Map.class)), hasEntry(equalTo("STR"), is("item: 50")))) .perform(click());
Espresso przewija listę automatycznie w razie potrzeby.
Przyjrzyjmy się urządzeniu Matcher<Object> w środku onData().
Metoda is(instanceOf(Map.class)) zawęża wyszukiwanie do dowolnego elementu
AdapterView, która jest wspierana przez obiekt Map.
W naszym przypadku ten aspekt zapytania pasuje do każdego wiersza widoku listy, ale chcemy kliknąć konkretny element, więc zawężamy wyszukiwanie dalej według tych kryteriów:
Kotlin
hasEntry(equalTo("STR"), `is`("item: 50"))
Java
hasEntry(equalTo("STR"), is("item: 50"))
Ten obiekt Matcher<String, Object> będzie pasować do każdej mapy zawierającej wpis z
klucz "STR" i wartość "item: 50". Ponieważ kod służący do wyszukiwania
Chcemy używać go w innych lokalizacjach,
withItemContent dopasowanie do tego wyniku:
Kotlin
return object : BoundedMatcher<Object, Map>(Map::class.java) { override fun matchesSafely(map: Map): Boolean { return hasEntry(equalTo("STR"), itemTextMatcher).matches(map) } override fun describeTo(description: Description) { description.appendText("with item content: ") itemTextMatcher.describeTo(description) } }
Java
return new BoundedMatcher<Object, Map>(Map.class) { @Override public boolean matchesSafely(Map map) { return hasEntry(equalTo("STR"), itemTextMatcher).matches(map); } @Override public void describeTo(Description description) { description.appendText("with item content: "); itemTextMatcher.describeTo(description); } };
Używa się funkcji BoundedMatcher jako podstawy, ponieważ dopasowujemy tylko obiekty danego typu.
Map Zastąp metodę matchesSafely(), dodając do znalezionego dopasowania
wcześniej i dopasuj ją do parametru Matcher<String>, który można przekazać jako
. Dzięki temu możesz zadzwonić pod numer withItemContent(equalTo("foo")). Aby uzyskać kod
możesz utworzyć kolejne dopasowanie, które wywołuje już operatory equalTo() i
akceptuje obiekt String:
Kotlin
fun withItemContent(expectedText: String): Matcher<Object> { checkNotNull(expectedText) return withItemContent(equalTo(expectedText)) }
Java
public static Matcher<Object> withItemContent(String expectedText) { checkNotNull(expectedText); return withItemContent(equalTo(expectedText)); }
Teraz kod, który trzeba kliknąć, jest prosty:
Kotlin
onData(withItemContent("item: 50")).perform(click())
Java
onData(withItemContent("item: 50")).perform(click());
Pełny kod tego testu znajduje się w metodzie testClickOnItem50()
w ciągu
AdapterViewTest.
klasa i
ten niestandardowy LongListMatchers
w usłudze GitHub.
Dopasowanie do konkretnego widoku podrzędnego
Powyższy przykład generuje kliknięcie w środku całego wiersza parametru ListView.
Co jednak, jeśli chcemy przeprowadzić działanie na konkretnym elemencie podrzędnym wiersza? Na przykład możemy
chce kliknąć drugą kolumnę w wierszu LongListActivity,
, który wyświetla wartość String.length zawartości pierwszej kolumny:

Wystarczy, że dodasz specyfikację onChildView() do swojej implementacji
DataInteraction:
Kotlin
onData(withItemContent("item: 60")) .onChildView(withId(R.id.item_size)) .perform(click())
Java
onData(withItemContent("item: 60")) .onChildView(withId(R.id.item_size)) .perform(click());
Interakcja z elementami listy widoku recyklingu
Obiekty RecyclerView działają inaczej niż obiekty AdapterView, więc
Nie możesz używać usługi onData() do interakcji z nimi.
Aby korzystać z obiektów RecyclerView za pomocą Espresso, możesz skorzystać z
Pakiet espresso-contrib, który zawiera kolekcję
RecyclerViewActions.
które pozwalają przewijać elementy w wybrane miejsca lub wykonywać na nich różne czynności:
scrollTo()– powoduje przewijanie do pasującego widoku, jeśli istnieje.scrollToHolder()– przewija stronę do pasującego właściciela widoku, jeśli istnieje.scrollToPosition()– przewija do określonej pozycji.actionOnHolderItem()– wykonuje czynność wyświetlenia w przypadku pasującego właściciela widoku.actionOnItem()– wykonuje działanie związane z wyświetleniem pasującego widoku danych.actionOnItemAtPosition()– wykonuje działania związane z widokiem danych w określonym miejscu.
Poniższe fragmenty kodu zawierają kilka przykładów RecyclerViewSample przykład:
Kotlin
@Test(expected = PerformException::class) fun itemWithText_doesNotExist() { // Attempt to scroll to an item that contains the special text. onView(ViewMatchers.withId(R.id.recyclerView)) .perform( // scrollTo will fail the test if no item matches. RecyclerViewActions.scrollTo( hasDescendant(withText("not in the list")) ) ) }
Java
@Test(expected = PerformException.class) public void itemWithText_doesNotExist() { // Attempt to scroll to an item that contains the special text. onView(ViewMatchers.withId(R.id.recyclerView)) // scrollTo will fail the test if no item matches. .perform(RecyclerViewActions.scrollTo( hasDescendant(withText("not in the list")) )); }
Kotlin
@Test fun scrollToItemBelowFold_checkItsText() { // First, scroll to the position that needs to be matched and click on it. onView(ViewMatchers.withId(R.id.recyclerView)) .perform( RecyclerViewActions.actionOnItemAtPosition( ITEM_BELOW_THE_FOLD, click() ) ) // Match the text in an item below the fold and check that it's displayed. val itemElementText = "${activityRule.activity.resources .getString(R.string.item_element_text)} ${ITEM_BELOW_THE_FOLD.toString()}" onView(withText(itemElementText)).check(matches(isDisplayed())) }
Java
@Test public void scrollToItemBelowFold_checkItsText() { // First, scroll to the position that needs to be matched and click on it. onView(ViewMatchers.withId(R.id.recyclerView)) .perform(RecyclerViewActions.actionOnItemAtPosition(ITEM_BELOW_THE_FOLD, click())); // Match the text in an item below the fold and check that it's displayed. String itemElementText = activityRule.getActivity().getResources() .getString(R.string.item_element_text) + String.valueOf(ITEM_BELOW_THE_FOLD); onView(withText(itemElementText)).check(matches(isDisplayed())); }
Kotlin
@Test fun itemInMiddleOfList_hasSpecialText() { // First, scroll to the view holder using the isInTheMiddle() matcher. onView(ViewMatchers.withId(R.id.recyclerView)) .perform(RecyclerViewActions.scrollToHolder(isInTheMiddle())) // Check that the item has the special text. val middleElementText = activityRule.activity.resources .getString(R.string.middle) onView(withText(middleElementText)).check(matches(isDisplayed())) }
Java
@Test public void itemInMiddleOfList_hasSpecialText() { // First, scroll to the view holder using the isInTheMiddle() matcher. onView(ViewMatchers.withId(R.id.recyclerView)) .perform(RecyclerViewActions.scrollToHolder(isInTheMiddle())); // Check that the item has the special text. String middleElementText = activityRule.getActivity().getResources() .getString(R.string.middle); onView(withText(middleElementText)).check(matches(isDisplayed())); }
Dodatkowe materiały
Więcej informacji o używaniu list Espresso w testach na Androidzie znajdziesz w poniższe zasoby.
Próbki
- DataAdapterSample:
Prezentuje punkt wejścia
onData()do Espresso, listy iAdapterViewobiektów.