Espresso menawarkan mekanisme untuk men-scroll atau bertindak pada item tertentu untuk dua jenis daftar: tampilan adaptor dan tampilan recycler.
Saat menangani daftar, terutama yang dibuat dengan objek RecyclerView
atau
AdapterView
, tampilan yang menjadi fokus Anda mungkin tidak muncul di
layar karena hanya sejumlah kecil turunan yang ditampilkan dan didaur ulang
saat Anda men-scroll. Metode scrollTo()
tidak dapat digunakan dalam kasus ini
karena memerlukan tampilan yang sudah ada.
Berinteraksi dengan item daftar tampilan adaptor
Daripada menggunakan metode onView()
, mulai penelusuran Anda dengan onData()
dan
berikan matcher terhadap data yang mendukung tampilan yang ingin Anda cocokkan.
Espresso akan melakukan semua pekerjaan menemukan baris dalam objek Adapter
dan
membuat item terlihat di area pandang.
Mencocokkan data menggunakan matcher tampilan kustom
Aktivitas di bawah ini berisi ListView
, yang didukung oleh SimpleAdapter
yang menyimpan data untuk setiap baris dalam objek Map<String, Object>
.
Setiap peta memiliki dua entri: "STR"
kunci yang berisi String, seperti
"item: x"
, dan kunci "LEN"
yang berisi Integer
, yang mewakili
panjang konten. Contoh:
{"STR" : "item: 0", "LEN": 7}
Kode untuk klik pada baris dengan "item: 50" terlihat seperti berikut:
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());
Perhatikan bahwa Espresso men-scroll daftar sesuai keperluan secara otomatis.
Mari kita pisahkan Matcher<Object>
di dalam onData()
. Metode
is(instanceOf(Map.class))
akan mempersempit penelusuran ke setiap item
AdapterView
, yang didukung oleh objek Map
.
Dalam kasus kita, aspek kueri ini cocok dengan setiap baris tampilan daftar, tetapi kita ingin mengklik secara khusus pada suatu item, jadi kita mempersempit penelusuran lebih lanjut dengan:
Kotlin
hasEntry(equalTo("STR"), `is`("item: 50"))
Java
hasEntry(equalTo("STR"), is("item: 50"))
Matcher<String, Object>
ini akan cocok dengan Peta apa pun yang berisi entri dengan kunci "STR"
dan nilai "item: 50"
. Karena kode untuk mencarinya
panjang dan kita ingin menggunakannya kembali di lokasi lain, mari kita tulis matcher
withItemContent
kustom untuk itu:
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); } };
Anda menggunakan BoundedMatcher
sebagai dasar karena hanya cocok dengan objek dengan jenis
Map
. Ganti metode matchesSafely()
, masukkan matcher yang ditemukan
sebelumnya, dan cocokkan dengan Matcher<String>
yang dapat Anda teruskan sebagai
argumen. Hal ini memungkinkan Anda untuk memanggil withItemContent(equalTo("foo"))
. Agar kode
singkat, Anda dapat membuat matcher lain yang sudah memanggil equalTo()
dan
menerima objek 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)); }
Sekarang, kode untuk mengklik item sederhana:
Kotlin
onData(withItemContent("item: 50")).perform(click())
Java
onData(withItemContent("item: 50")).perform(click());
Untuk kode lengkap pengujian ini, lihat metode testClickOnItem50()
dalam class
AdapterViewTest
dan pencocok LongListMatchers
kustom ini di GitHub.
Mencocokkan tampilan turunan tertentu
Contoh di atas memunculkan klik di tengah-tengah seluruh baris ListView
.
Namun, bagaimana jika kita ingin beroperasi pada turunan tertentu dari barisan tersebut? Misalnya, kita
ingin mengklik kolom kedua dari baris LongListActivity
,
yang menampilkan String.length konten di kolom pertama:
Cukup tambahkan spesifikasi onChildView()
ke implementasi
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());
Berinteraksi dengan item daftar tampilan recycler
Objek RecyclerView
berfungsi secara berbeda dari objek AdapterView
, sehingga
onData()
tidak dapat digunakan untuk berinteraksi dengannya.
Untuk berinteraksi dengan RecyclerViews menggunakan Espresso, Anda dapat menggunakan
paket espresso-contrib
, yang memiliki kumpulan
RecyclerViewActions
yang dapat digunakan untuk men-scroll ke posisi atau melakukan tindakan pada item:
scrollTo()
- Men-scroll ke Tampilan yang cocok, jika ada.scrollToHolder()
- Men-scroll ke Holder Tampilan yang cocok, jika ada.scrollToPosition()
- Men-scroll ke posisi tertentu.actionOnHolderItem()
- Menjalankan Tindakan Tampilan pada Holder Tampilan yang cocok.actionOnItem()
- Menjalankan Tindakan Tampilan pada Tampilan yang cocok.actionOnItemAtPosition()
- Menjalankan ViewAction pada tampilan di posisi tertentu.
Cuplikan berikut menampilkan beberapa contoh dari contoh RecyclerViewSample:
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())); }
Referensi lainnya
Untuk informasi selengkapnya tentang penggunaan daftar Espresso dalam pengujian Android, lihat referensi berikut.
Contoh
- DataAdapterSample:
Menampilkan titik entri
onData()
untuk Espresso, untuk daftar, dan objekAdapterView
.