Espresso offre meccanismi per scorrere o agire su un particolare oggetto per due tipi di elenchi: viste adattatori e viste riciclatore.
Quando si gestiscono le liste, in particolare quelle create con un RecyclerView
o un
AdapterView
oggetto, la visualizzazione che ti interessa potrebbe non essere nemmeno
della schermata perché è visualizzato solo un numero limitato di bambini
riciclato durante lo scorrimento. Il metodo scrollTo()
non può essere utilizzato in questo caso
perché richiede una vista esistente.
Interagire con le voci dell'elenco della visualizzazione adattatori
Anziché utilizzare il metodo onView()
, inizia la tua ricerca con onData()
e
fornire un matcher per i dati su cui si basa la vista per la quale vuoi creare una corrispondenza.
Espresso si occuperà di trovare la riga nell'oggetto Adapter
e
rendendo visibile l'elemento
nell'area visibile.
Abbina i dati utilizzando un matcher vista personalizzato
L'attività seguente contiene un ListView
, che è supportato da un SimpleAdapter
che contiene i dati per ogni riga in un oggetto Map<String, Object>
.
Ogni mappa ha due voci: una chiave "STR"
contenente una stringa, come
"item: x"
e una chiave "LEN"
che contiene Integer
, che rappresenta
la lunghezza dei contenuti. Ad esempio:
{"STR" : "item: 0", "LEN": 7}
Il codice per un clic sulla riga con "item: 50" ha il seguente aspetto:
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());
Tieni presente che Espresso scorre automaticamente l'elenco, se necessario.
Smontiamo Matcher<Object>
all'interno di onData()
. La
is(instanceOf(Map.class))
restringe la ricerca a qualsiasi elemento di
AdapterView
, supportato da un oggetto Map
.
Nel nostro caso, questo aspetto della query corrisponde a ogni riga della visualizzazione elenco, ma quando vuoi fare clic su un elemento specifico, restringiamo ulteriormente la ricerca con:
Kotlin
hasEntry(equalTo("STR"), `is`("item: 50"))
Java
hasEntry(equalTo("STR"), is("item: 50"))
Questo Matcher<String, Object>
corrisponderà a qualsiasi mappa contenente una voce con
la chiave "STR"
e il valore "item: 50"
. Poiché il codice per cercare è
e vogliamo riutilizzarlo in altre posizioni, creiamo un'immagine
withItemContent
corrispondente:
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); } };
Utilizzi un BoundedMatcher
come base perché per trovare corrispondenze solo per oggetti di tipo
Map
. Sostituisci il metodo matchesSafely()
inserendo il matcher trovato
e confrontarlo con un Matcher<String>
che puoi passare come
. Questo ti consente di chiamare withItemContent(equalTo("foo"))
. Per il codice
brevità, puoi creare un altro matcher che chiama già equalTo()
e
accetta un oggetto 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)); }
Ora il codice per fare clic sull'elemento è semplice:
Kotlin
onData(withItemContent("item: 50")).perform(click())
Java
onData(withItemContent("item: 50")).perform(click());
Per il codice completo di questo test, dai un'occhiata al metodo testClickOnItem50()
all'interno
AdapterViewTest
classe e
questa LongListMatchers
personalizzata
su GitHub.
Associare una vista secondaria specifica
L'esempio precedente genera un clic al centro dell'intera riga di un ListView
.
E se volessimo operare su un elemento figlio specifico della riga? Ad esempio,
fare clic sulla seconda colonna della riga LongListActivity
,
che visualizza il valore String.length dei contenuti nella prima colonna:
È sufficiente aggiungere una specifica onChildView()
all'implementazione
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());
Interagire con gli elementi dell'elenco della visualizzazione del riciclatore
RecyclerView
oggetti funzionano in modo diverso rispetto a AdapterView
oggetti, quindi
Impossibile utilizzare onData()
per interagire.
Per interagire con RecyclerView utilizzando Espresso, puoi utilizzare lo
espresso-contrib
, che contiene una raccolta di
RecyclerViewActions
che può essere utilizzato per scorrere le posizioni o eseguire azioni sugli elementi:
scrollTo()
: scorre fino alla vista corrispondente, se esistente.scrollToHolder()
: scorre fino al contenitore della vista corrispondente, se esistente.scrollToPosition()
: consente di scorrere fino a una posizione specifica.actionOnHolderItem()
: esegue un'azione di visualizzazione su un titolare della vista corrispondente.actionOnItem()
: esegue un'azione di visualizzazione su una vista con corrispondenza.actionOnItemAtPosition()
: esegue un'azione ViewAction su una vista in una posizione specifica.
I seguenti snippet presentano alcuni esempi Esempio di visualizzazione del riciclo esempio:
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())); }
Risorse aggiuntive
Per ulteriori informazioni sull'utilizzo degli elenchi Espresso nei test Android, consulta il le seguenti risorse.
Campioni
- DataAdapterSample:
Mette in evidenza il punto di accesso
onData()
per Espresso, per liste eAdapterView
di oggetti strutturati.