Wie in einem RecyclerView in Espresso behaupten?

Lesezeit: 7 Minuten

Benutzer-Avatar
juhlila

Ich verwende espresso-contrib, um Aktionen auf a auszuführen RecyclerViewund es funktioniert wie es sollte, z.

//click on first item
onView(withId(R.id.recycler_view))
    .perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));

und ich muss Assertionen darauf durchführen. Etwas wie das:

onView(withId(R.id.recycler_view))
    .perform(
        RecyclerViewActions.actionOnItemAtPosition(
            0, check(matches(withText("Test Text")))
        )
    );

aber weil RecyclerViewActions erwartet natürlich eine Aktion, da steht falscher 2. Argumenttyp. Da ist kein RecyclerViewAssertions auf Espresso-Beitrag.

Gibt es eine Möglichkeit, Behauptungen auf a auszuführen RecyclerView?

  • Vielleicht könnte die Antwort auf diese ähnliche SO-Frage helfen

    – Francislainy Campos

    17. Oktober 2018 um 10:23 Uhr

Benutzer-Avatar
riwnodennyk

Ziemlich einfach. Es wird keine zusätzliche Bibliothek benötigt. Tun:

    onView(withId(R.id.recycler_view))
            .check(matches(atPosition(0, withText("Test Text"))));

Wenn Ihr ViewHolder ViewGroup verwendet, Wrap withText() mit einer hasDescendant() wie:

onView(withId(R.id.recycler_view))
                .check(matches(atPosition(0, hasDescendant(withText("Test Text")))));

mit Methode, die Sie in Ihre setzen können Utils Klasse.

public static Matcher<View> atPosition(final int position, @NonNull final Matcher<View> itemMatcher) {
    checkNotNull(itemMatcher);
    return new BoundedMatcher<View, RecyclerView>(RecyclerView.class) {
        @Override
        public void describeTo(Description description) {
            description.appendText("has item at position " + position + ": ");
            itemMatcher.describeTo(description);
        }

        @Override
        protected boolean matchesSafely(final RecyclerView view) {
            RecyclerView.ViewHolder viewHolder = view.findViewHolderForAdapterPosition(position);
            if (viewHolder == null) {
                // has no item on such position
                return false;
            }
            return itemMatcher.matches(viewHolder.itemView);
        }
    };
}

Wenn Ihr Artikel zunächst nicht auf dem Bildschirm sichtbar ist, scrollen Sie vorher dorthin:

    onView(withId(R.id.recycler_view))
            .perform(scrollToPosition(87))
            .check(matches(atPosition(87, withText("Test Text"))));

  • .perform(scrollToPosition(87)) funktioniert nicht. Test schlägt fehl

    – Prajwal Waingankar

    12. April um 16:17 Uhr

  • Diese Lösung funktioniert, aber im Fehlerfall werden Details darüber gedruckt RecyclerView selbst, nicht über das Element an Position N, sodass Sie möglicherweise Schwierigkeiten haben, herauszufinden, was falsch ist. Für Matcher mit besserer Diagnose können Sie sich meine Lösung oder einige der anderen ansehen

    – gmk57

    3. Mai um 22:09 Uhr

Benutzer-Avatar
HowieH

Sie sollten sich die Lösung von Danny Roa ansehen Benutzerdefinierte RecyclerView-Aktionen
Und benutze es so:

onView(withRecyclerView(R.id.recycler_view)
    .atPositionOnView(1, R.id.ofElementYouWantToCheck))
    .check(matches(withText("Test text")));

  • Funktioniert bei mir nicht, wenn das Element an dieser Position derzeit nicht auf den Bildschirm passt.

    – riwnodennyk

    14. Januar 2016 um 16:11 Uhr


  • Versuchen Sie zuerst, zur Position zu scrollen? onView(withId(R.id.id.recycler_view)).perform(RecyclerViewActions.scrollTo(2));

    – HowieH

    15. Januar 2016 um 12:32 Uhr

  • Immer noch die gleichen. Funktioniert zB nicht für Position = 30. Das Problem ist das RecyclerView.findViewHolderForAdapterPosition(position) verwendet werden soll RecyclerView.getChildAt() wie in der Antwort unten gezeigt wurde.

    – riwnodennyk

    16. Januar 2016 um 0:35 Uhr


  • Funktioniert immer noch nicht für mich, wenn das Element außerhalb des Bildschirms ist, ich habe den findViewHolderForAdapterPosition(position) zum RecyclerViewMatcher hinzugefügt. Wenn ich das mache: onView(withRecyclerView(R.id.synology_apps_rv).atPositionOnView(7, R.id.not_installed_tv)).check(matches(withText(R.string.notinstalled))); Der Test schlägt fehl, aber wenn ich das mache: onView(withId(R.id.synology_apps_rv)).perform(RecyclerViewActions.scrollToPosition(7));onView(withRecyclerView(R.id.synology_apps_rv).atPositionOnView(7, R.id .not_installed_tv)).check(matches(withText(R.string.notinstalled))); die Prüfung ist gelungen

    – Koen Van Looveren

    6. November 2016 um 8:55 Uhr


  • Was ist, wenn Sie mehr als eine Recycler-Ansicht mit derselben ID haben?

    – Damia Fuentes

    5. September 2017 um 15:01 Uhr

Benutzer-Avatar
Du Qi

Nur um die Antwort von Riwnodennyk zu verbessern, wenn Sie ViewHolder ist ein ViewGroup statt direkt View Objekt wie TextViewdann können Sie hinzufügen hasDescendant Matcher passend zum TextView Objekt in der ViewGroup. Beispiel:

onView(withId(R.id.recycler_view))
    .check(matches(atPosition(0, hasDescendant(withText("First Element")))));

  • Perfekt, mir fehlte nur noch der hasDescendantVielen Dank!

    – Rob Holmes

    17. Oktober 2017 um 21:33 Uhr

Benutzer-Avatar
Hiten Bahri

Ich habe mit demselben Problem zu kämpfen, bei dem ich eine Recycler-Ansicht mit 6 Elementen habe und dann die an Position 5 auswählen muss und die 5. in der Ansicht nicht sichtbar ist.
Die obige Lösung funktioniert auch. Ich weiß auch, dass es ein bisschen spät ist, aber ich dachte, es lohnt sich, es zu teilen.

Ich tat dies mit einer einfachen Lösung wie folgt:

onView(withId(R.id.recylcer_view))
    .perform(RecyclerViewActions.actionOnItem(
         hasDescendant(withText("Text of item you want to scroll to")), 
         click()));

RecyclerViewActions.actionOnItem – Führt ein ViewAction auf eine Ansicht von abgestimmt viewHolderMatcher.

  1. Scrollen RecyclerView zu der Ansicht passte von itemViewMatcher
  2. Führen Sie eine Aktion für die übereinstimmende Ansicht aus

Weitere Einzelheiten finden Sie unter: RecyclerViewActions.actionOnItem

Benutzer-Avatar
Vince

In meinem Fall war es notwendig, die Lösung von Danny Roa und riwnodennyk zusammenzuführen:

onView(withId(R.id.recyclerview))
.perform(RecyclerViewActions.scrollToPosition(80))
.check(matches(atPositionOnView(80, withText("Test Test"), R.id.targetview)));

und die Methode:

public static Matcher<View> atPositionOnView(final int position, final Matcher<View> itemMatcher,
        final int targetViewId) {

    return new BoundedMatcher<View, RecyclerView>(RecyclerView.class) {
        @Override
        public void describeTo(Description description) {
            description.appendText("has view id " + itemMatcher + " at position " + position);
        }

        @Override
        public boolean matchesSafely(final RecyclerView recyclerView) {
            RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(position);
            View targetView = viewHolder.itemView.findViewById(targetViewId);
            return itemMatcher.matches(targetView);
        }
    };
}

  • Es funktioniert immer noch nicht. Es versucht, den Text „Test Test“ in einer RecyclerView-Instanz zu überprüfen, nicht in der Zielansicht.

    – tomrozb

    7. September 2016 um 23:47 Uhr

  • können Sie das Matcher-Importpaket freigeben

    – 1’hafs

    10. November 2017 um 14:02 Uhr

  • import org.hamcrest.Matcher (aus hamcrest-core-1.3)

    – Vince

    11. November 2017 um 17:45 Uhr

  • Mir ist nicht klar, wie ich die bekommen soll targetViewId um es als Parameter an zu übergeben atPositionOnView

    – Ein Droide

    24. Februar 2018 um 17:09 Uhr

  • Grundsätzlich kenne ich die ID des Artikels vorher nicht, da sie jedes Mal, wenn ich den Test durchführe, anders sein könnte. Es könnte ein TextView, ein Button oder etwas anderes sein.

    – Ein Droide

    24. Februar 2018 um 17:25 Uhr

Für Kotlin-Benutzer: Ich weiß, dass ich sehr spät dran bin, und ich bin verwirrt, warum die Leute RecycleView-Aktionen anpassen müssen. Ich wollte genau das gleiche gewünschte Ergebnis erzielen: Hier ist meine Lösung, ich hoffe, sie funktioniert und hilft Neulingen. Seien Sie auch vorsichtig mit mir, da ich möglicherweise blockiert werde.

onView(withId(R.id.recycler_view))
.perform(actionOnItemAtPosition<ViewHolder>(46, scrollTo()))
.check(matches(hasDescendant(withText("TextToMatch"))))

//Bearbeitet am 18.12.21: Nachdem Sie Björns Kommentar untersucht haben, sehen Sie bitte unten einen besseren Ansatz:

onView(withId(R.id.recyclerView))
.perform(RecyclerViewActions.scrollToPosition<ViewHolder>(12))
.check(matches(hasDescendant(withText("TexttoMatch"))))

  • Es funktioniert immer noch nicht. Es versucht, den Text „Test Test“ in einer RecyclerView-Instanz zu überprüfen, nicht in der Zielansicht.

    – tomrozb

    7. September 2016 um 23:47 Uhr

  • können Sie das Matcher-Importpaket freigeben

    – 1’hafs

    10. November 2017 um 14:02 Uhr

  • import org.hamcrest.Matcher (aus hamcrest-core-1.3)

    – Vince

    11. November 2017 um 17:45 Uhr

  • Mir ist nicht klar, wie ich die bekommen soll targetViewId um es als Parameter an zu übergeben atPositionOnView

    – Ein Droide

    24. Februar 2018 um 17:09 Uhr

  • Grundsätzlich kenne ich die ID des Artikels vorher nicht, da sie jedes Mal, wenn ich den Test durchführe, anders sein könnte. Es könnte ein TextView, ein Button oder etwas anderes sein.

    – Ein Droide

    24. Februar 2018 um 17:25 Uhr

Benutzer-Avatar
Thomas

Ich habe ein paar Antworten oben zu einer wiederverwendbaren Methode zum Testen anderer Recycler-Ansichten kombiniert, wenn das Projekt wächst. Lassen Sie den Code hier, falls er jemand anderem hilft …

Deklarieren Sie eine Funktion, die für eine RecyclerView-Ressourcen-ID aufgerufen werden kann:

fun Int.shouldHaveTextAtPosition(text:String, position: Int) {
    onView(withId(this))
        .perform(scrollToPosition<RecyclerView.ViewHolder>(position))
        .check(matches(atPosition(position, hasDescendant(withText(text)))))
}

Rufen Sie es dann in Ihrer Recycler-Ansicht auf, um den angezeigten Text mehrerer Adapterelemente in der Liste an einer bestimmten Position zu überprüfen, indem Sie Folgendes tun:

with(R.id.recycler_view_id) {
    shouldHaveTextAtPosition("Some Text at position 0", 0)
    shouldHaveTextAtPosition("Some Text at position 1", 1)
    shouldHaveTextAtPosition("Some Text at position 2", 2)
    shouldHaveTextAtPosition("Some Text at position 3", 3)
}

  • Ich bin mir schon eine Weile nicht sicher, welche Abhängigkeitsversionen erforderlich sind, damit dieser Code ausgeführt werden kann. Wenn ich etwas Freizeit habe, werde ich versuchen, zurückzugehen und sie zu finden.

    – Thomas

    22. März 2021 um 13:48 Uhr

1176510cookie-checkWie in einem RecyclerView in Espresso behaupten?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy