Daftar Espresso

Espresso menawarkan mekanisme untuk men-scroll atau bertindak pada item tertentu untuk dua jenis daftar: tampilan adapter dan tampilan recycler.

Saat menangani daftar, terutama yang dibuat dengan objek RecyclerView atau AdapterView, tampilan yang diminati bisa saja tidak ada 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 ada.

Berinteraksi dengan item daftar tampilan adapter

Dari pada menggunakan metode onView(), mulai penelusuran 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 dapat dilihat 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>.

Aktivitas daftar yang ditampilkan di layar berisi daftar dengan 23 item. Setiap item memiliki nomor, disimpan sebagai String, dipetakan ke nomor yang berbeda, yang disimpan sebagai Objek.

Setiap peta memiliki dua entri: kunci "STR" yang berisi String, seperti "item: x", dan kunci "LEN" yang berisi Integer, yang mewakili panjang konten. Misalnya:

    {"STR" : "item: 0", "LEN": 7}
    

Kode untuk klik pada baris dengan "item: 50" terlihat seperti berikut:

Kotlin

    onData(allOf(`is`(instanceOf(Map.class)), 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 otomatis men-scroll daftar sesuai keperluan.

Mari kita pisahkan Matcher<Object> di dalam onData(). Metode is(instanceOf(Map.class)) akan mempersempit penelusuran ke item AdapterView apa pun, 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, sehingga 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 semua Peta yang berisi entri dengan kunci "STR" dan nilai "item: 50". Karena kode untuk mencarinya panjang dan kita ingin menggunakannya kembali di lokasi lain, mari menulis 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 jenis Map. Ganti metode matchesSafely(), masukkan matcher yang ditemukan sebelumnya, dan cocokkan dengan Matcher<String> yang dapat Anda teruskan sebagai argumen. Langkah ini memungkinkan Anda untuk memanggil withItemContent(equalTo("foo")). Agar kode ringkas, 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 pengujian ini selengkapnya, lihat metode testClickOnItem50() dalam class AdapterViewTest dan matcher LongListMatchers kustom ini di GitHub.

Mencocokkan tampilan turunan tertentu

Contoh di atas memberikan klik di tengah-tengah seluruh baris ListView. Tetapi, bagaimana jika kita ingin beroperasi pada turunan tertentu barisan? Misalnya, kita ingin mengklik kolom kedua dari baris LongListActivity, yang menampilkan panjang String konten di kolom pertama:

Dalam contoh ini, akan bermanfaat untuk mengekstrak hanya panjang konten tertentu. Proses ini melibatkan penentuan nilai kolom kedua secara berturut-turut.

Cukup tambahkan spesifikasi onChildView() untuk 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 koleksi RecyclerViewActions dan dapat digunakan untuk men-scroll ke posisi atau menjalankan tindakan pada item:

  • scrollTo() - Men-scroll ke Tampilan yang cocok.
  • scrollToHolder() - Men-scroll ke Holder Tampilan yang cocok.
  • scrollToPosition() - Men-scroll ke posisi tertentu.
  • actionOnHolderItem() - Menjalankan Tindakan Tampilan di Holder Tampilan yang cocok.
  • actionOnItem() - Menjalankan Tindakan Tampilan di Tampilan yang cocok.
  • actionOnItemAtPosition() - Menjalankan ViewAction di tampilan pada posisi tertentu.

Cuplikan berikut menampilkan beberapa contoh dari RecyclerViewSample:

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 menggunakan daftar Espresso dalam pengujian Android, lihat referensi berikut.

Contoh

  • DataAdapterSample: Menampilkan titik masuk onData() untuk Espresso, untuk daftar dan objek AdapterView.