Espresso bietet zwei Möglichkeiten, zu einem bestimmten Element zu scrollen oder eine Aktion auszuführen. Listentypen: Adapteransichten und Recycler-Ansichten.
Beim Umgang mit Listen, insbesondere solchen, die mit einem RecyclerView
oder einem
AdapterView
-Objekt enthält, befindet sich die Ansicht, an der Sie interessiert sind, möglicherweise
da nur eine kleine Anzahl untergeordneter Elemente
wenn Sie scrollen. Die Methode scrollTo()
kann in diesem Fall nicht verwendet werden
da hierfür eine vorhandene
Ansicht erforderlich ist.
Mit Listenelementen der Adapteransicht interagieren
Anstatt die Methode onView()
zu verwenden, beginnen Sie Ihre Suche mit onData()
und
einen Abgleich mit den Daten bereitstellen, die die zu abgleichende Ansicht unterstützen.
Espresso sucht dann die Zeile im Adapter
-Objekt und
sodass das Element im Darstellungsbereich sichtbar wird.
Daten mithilfe eines benutzerdefinierten Abgleichs-Matchers abgleichen
Die Aktivität unten enthält ein ListView
-Element mit einem SimpleAdapter
-Element
enthält Daten für jede Zeile in einem Map<String, Object>
-Objekt.
Jede Zuordnung hat zwei Einträge: einen Schlüssel-"STR"
, der einen String enthält, z. B.
"item: x"
und einem Schlüssel "LEN"
, der eine Integer
enthält, die den
Länge des Inhalts. Beispiel:
{"STR" : "item: 0", "LEN": 7}
Der Code für einen Klick auf die Zeile mit „item: 50“ sieht so aus:
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());
Beachten Sie, dass Espresso bei Bedarf automatisch durch die Liste scrollt.
Nehmen wir das Matcher<Object>
in onData()
auseinander. Die
is(instanceOf(Map.class))
beschränkt die Suche auf ein beliebiges Element der
AdapterView
, die von einem Map
-Objekt gestützt wird.
In unserem Fall stimmt dieser Aspekt der Abfrage mit jeder Zeile der Listenansicht überein, auf ein Element klicken möchten, grenzen wir die Suche daher weiter ein:
Kotlin
hasEntry(equalTo("STR"), `is`("item: 50"))
Java
hasEntry(equalTo("STR"), is("item: 50"))
Dieses Matcher<String, Object>
stimmt mit jeder Karte überein, die einen Eintrag mit
den Schlüssel "STR"
und den Wert "item: 50"
. Da der Code zum Suchen
und sie auch an anderen Stellen wiederverwenden möchten. Schreiben wir nun eine benutzerdefinierte
withItemContent
-Matcher dafür:
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); } };
Sie verwenden eine BoundedMatcher
als Basis, da nur Objekte des Typs abgeglichen werden
Map
. matchesSafely()
-Methode überschreiben und den gefundenen Matcher einfügen
und sie mit einer Matcher<String>
abgleichen, die Sie als
. So können Sie withItemContent(equalTo("foo"))
aufrufen. Für Code
können Sie einen weiteren Matcher erstellen, der bereits die equalTo()
und
akzeptiert ein String
-Objekt:
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)); }
Jetzt ist der Code zum Klicken auf das Element einfach:
Kotlin
onData(withItemContent("item: 50")).perform(click())
Java
onData(withItemContent("item: 50")).perform(click());
Den vollständigen Code für diesen Test finden Sie in der testClickOnItem50()
-Methode
im
AdapterViewTest
Klasse und
dieser benutzerdefinierten LongListMatchers
Matcher auf GitHub.
Mit einer bestimmten untergeordneten Ansicht abgleichen
Das Beispiel oben gibt einen Klick in der Mitte der gesamten Zeile eines ListView
aus.
Aber was ist, wenn wir für ein bestimmtes untergeordnetes Element der Zeile arbeiten möchten? Zum Beispiel
auf die zweite Spalte in der Zeile von LongListActivity
klicken möchte,
mit der String.length des Inhalts in der ersten Spalte angezeigt wird:
Fügen Sie einfach eine onChildView()
-Spezifikation zu Ihrer Implementierung von
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());
Mit Listenelementen der Recycler-Ansicht interagieren
RecyclerView
-Objekte funktionieren anders als AdapterView
-Objekte.
onData()
kann nicht für die Interaktion mit ihnen verwendet werden.
Um über Espresso mit RecyclerViews zu interagieren, können Sie die
espresso-contrib
-Paket mit einer Sammlung von
RecyclerViewActions
mit dem Sie zu bestimmten Positionen scrollen oder Aktionen für Elemente ausführen können:
scrollTo()
: Hiermit wird zur übereinstimmenden Ansicht gescrollt, sofern vorhanden.scrollToHolder()
: Hiermit wird zum übereinstimmenden Ansichtsinhaber gescrollt, sofern vorhanden.scrollToPosition()
: Scrollt zu einer bestimmten Position.actionOnHolderItem()
: Führt eine Aufrufaktion für einen übereinstimmenden View-Holder aus.actionOnItem()
: Führt eine Aufrufaktion für einen übereinstimmenden Aufruf aus.actionOnItemAtPosition()
: Führt eine ViewAction für einen Aufruf an einer bestimmten Position aus.
Die folgenden Snippets enthalten einige Beispiele aus dem RecyclerViewSample Beispiel:
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())); }
Weitere Informationen
Weitere Informationen zur Verwendung von Espressolisten in Android-Tests finden Sie in der in den folgenden Ressourcen.
Produktproben
- DataAdapterSample:
Zeigt den
onData()
-Einstiegspunkt für Espresso, für Listen undAdapterView
Objekte.