Espresso propose des mécanismes permettant de faire défiler jusqu'à un élément particulier ou d'agir dessus pendant deux types de listes: vues d'adaptateur et vues recycleur.
Lorsque vous avez affaire à des listes, en particulier celles créées avec un RecyclerView
ou un
AdapterView
, la vue qui vous intéresse n'est peut-être pas
l'écran, car seul un petit nombre d'enfants s'affiche et sont
est recyclée lorsque vous faites défiler. La méthode scrollTo()
ne peut pas être utilisée dans ce cas.
car cela nécessite une vue existante.
Interagir avec les éléments de la liste de la vue de l'adaptateur
Au lieu d'utiliser la méthode onView()
, commencez votre recherche avec onData()
et
fournir une mise en correspondance avec les données qui soutiennent la vue que vous souhaitez mettre en correspondance.
Espresso se charge de rechercher la ligne dans l'objet Adapter
.
qui rend l'élément visible
dans la fenêtre d'affichage.
Mettre en correspondance des données à l'aide d'un outil de mise en correspondance des vues personnalisé
L'activité ci-dessous contient un ListView
, qui repose sur un SimpleAdapter
.
qui contient les données de chaque ligne d'un objet Map<String, Object>
.
Chaque mappage comporte deux entrées: une clé "STR"
contenant une chaîne, telle que
"item: x"
et une clé "LEN"
contenant un Integer
, qui représente le
la longueur du contenu. Exemple :
{"STR" : "item: 0", "LEN": 7}
Code pour un clic sur la ligne contenant "item: 50" se présente comme suit:
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());
Notez qu'Espresso fait défiler automatiquement la liste si nécessaire.
Démontons le Matcher<Object>
dans onData()
. La
La méthode is(instanceOf(Map.class))
limite la recherche à n'importe quel élément de
AdapterView
, qui repose sur un objet Map
.
Dans notre cas, cet aspect de la requête correspond à chaque ligne de la vue sous forme de liste, mais nous si vous souhaitez cliquer sur un article en particulier, nous restreignons la recherche avec:
Kotlin
hasEntry(equalTo("STR"), `is`("item: 50"))
Java
hasEntry(equalTo("STR"), is("item: 50"))
Ce Matcher<String, Object>
correspondra à toute Map contenant une entrée avec
la clé "STR"
et la valeur "item: 50"
. Comme le code pour les rechercher est
et que nous voulons le réutiliser dans d'autres emplacements, écrivons
withItemContent
pour cela:
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); } };
Vous utilisez un BoundedMatcher
comme base, car pour faire correspondre uniquement les objets de type
Map
Remplacez la méthode matchesSafely()
en plaçant l'outil de mise en correspondance trouvé.
et les comparer à un Matcher<String>
que vous pouvez transmettre
. Cela vous permet d'appeler withItemContent(equalTo("foo"))
. Pour code
vous pouvez créer un autre outil de mise en correspondance qui appelle déjà equalTo()
.
accepte un objet 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)); }
Désormais, le code permettant de cliquer sur l'élément est simple:
Kotlin
onData(withItemContent("item: 50")).perform(click())
Java
onData(withItemContent("item: 50")).perform(click());
Pour obtenir le code complet de ce test, consultez la méthode testClickOnItem50()
.
dans la
AdapterViewTest
classe et
ce LongListMatchers
personnalisé
sur GitHub.
Faire correspondre à une vue enfant spécifique
L'exemple ci-dessus génère un clic au milieu de la ligne entière d'un élément ListView
.
Mais que se passe-t-il si nous voulons opérer sur un enfant spécifique de la ligne ? Par exemple, nous
souhaite cliquer sur la deuxième colonne de la ligne du LongListActivity
,
qui affiche la chaîne String.length du contenu dans la première colonne:
Il vous suffit d'ajouter une spécification onChildView()
à votre implémentation de
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());
Interagir avec les éléments de la liste de la vue RecyclerView
Les objets RecyclerView
fonctionnent différemment des objets AdapterView
. Par conséquent,
Vous ne pouvez pas utiliser onData()
pour interagir avec elles.
Pour interagir avec les RecyclerViews à l'aide d'Espresso, vous pouvez utiliser le
Le package espresso-contrib
, qui comporte un ensemble de
RecyclerViewActions
permettant de faire défiler l'écran jusqu'à une position ou d'effectuer des actions sur des éléments:
scrollTo()
: fait défiler l'écran jusqu'à la vue correspondante, le cas échéant.scrollToHolder()
: fait défiler la page jusqu'au conteneur de la vue correspondant, le cas échéant.scrollToPosition()
: fait défiler l'écran jusqu'à une position spécifique.actionOnHolderItem()
: exécute une action de vue sur un conteneur de vue correspondant.actionOnItem()
: exécute une action d'affichage sur une vue correspondante.actionOnItemAtPosition()
: exécute une ViewAction sur une vue à une position spécifique.
Les extraits de code suivants contiennent quelques exemples du Exemple RecyclerView exemple:
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())); }
Ressources supplémentaires
Pour en savoir plus sur l'utilisation des listes Espresso dans les tests Android, consultez le les ressources suivantes.
Exemples
- DataAdapterSample:
Présente le point d'entrée
onData()
d'Espresso, pour les listes etAdapterView
d'objets.