Ich habe eine RecyclerView (R.id.recyclerView), in der jede Zeile ein Bild (R.id.row_image) und eine TextView hat. Ich möchte auf das Bild in der ersten Reihe klicken.
Ich habe versucht, onData (..) zu verwenden, aber es scheint nicht zu funktionieren.
Verwenden Sie RecyclerViewActions
onView(withId(R.id.recyclerView))
.perform(actionOnItemAtPosition(0, click()));
Fügen Sie dies in Ihr Gradle-Skript ein:
dependencies {
androidTestCompile 'com.Android.support.test:testing-support-lib:0.1'
androidTestCompile 'com.Android.support.test.espresso:espresso-core:2.0'
androidTestCompile 'com.Android.support.test.espresso:espresso-contrib:2.0'
}
Nur um Gabors Antwort hinzuzufügen (was seit Espresso 2.0 die richtige und vollständige Antwort ist).
Bei der Verwendung von espresso-contrib
und RecyclerView
s können derzeit Probleme auftreten (siehe Android-Test-Kit-Ticket ).
Eine Problemumgehung besteht darin, diesen Ausschluss in der oben genannten espresso-contrib
-Abhängigkeit von Gabor hinzuzufügen:
androidTestCompile('com.Android.support.test.espresso:espresso-contrib:2.0') {
exclude group: 'com.Android.support', module: 'appcompat'
exclude group: 'com.Android.support', module: 'support-v4'
exclude module: 'recyclerview-v7'
}
(Dies ist eine Antwort statt eines Kommentars zu Gabors Antwort, da ich noch nicht das Recht habe, Kommentare zu schreiben.)
Espresso 2.0 wurde veröffentlicht, das Änderungsprotokoll enthält Folgendes:
Neue Eigenschaften
- espresso-Beitrag
- RecyclerViewActions: Behandelt Interaktionen mit RecyclerViews
Ich habe das noch nicht selbst getestet, aber Thomas Keller postete dies auf G + mit einer kurzen Erklärung und einem Link zu einem Gist mit den erforderlichen View-Matchern.
Da die neue
RecyclerView
-API vonViewGroup
und nicht vonAdapterView
erbt, können Sie EspressosonData()
nicht zum Testen von Layouts mit dieser Komponente verwenden.
Ich werde den Code nur der Vollständigkeit halber beifügen (Anmerkung: nicht meins! Alle Gutschriften gehen an Thomas Keller)
ViewMatcher:
public class ViewMatchers {
@SuppressWarnings("unchecked")
public static Matcher<View> withRecyclerView(@IdRes int viewId) {
return allOf(isAssignableFrom(RecyclerView.class), withId(viewId));
}
@SuppressWarnings("unchecked")
public static ViewInteraction onRecyclerItemView(@IdRes int identifyingView, Matcher<View> identifyingMatcher, Matcher<View> childMatcher) {
Matcher<View> itemView = allOf(withParent(withRecyclerView(R.id.start_grid)),
withChild(allOf(withId(identifyingView), identifyingMatcher)));
return Espresso.onView(allOf(isDescendantOfA(itemView), childMatcher));
}
}
Und beispielverwendung:
onRecyclerItemView(R.id.item_title, withText("Test"), withId(R.id.item_content))
.matches(check(withText("Test Content")));
Sie sollten eine benutzerdefinierte ViewAction verwenden:
public void clickOnImageViewAtRow(int position) {
onView(withId(R.id.recycler_view)).perform(RecyclerViewActions.actionOnItemAtPosition(position, new ClickOnImageView()));
}
public class ClickOnImageView implements ViewAction{
ViewAction click = click();
@Override
public Matcher<View> getConstraints() {
return click.getConstraints();
}
@Override
public String getDescription() {
return " click on custom image view";
}
@Override
public void perform(UiController uiController, View view) {
click.perform(uiController, view.findViewById(R.id.imageView));
}
}
Ich habe zwei Möglichkeiten gefunden:
onView(allOf(withId(R.id.place_description),withText("what"))).perform(click());
`
public Matcher<View> withItemText(final String itemText) {
checkArgument(!TextUtils.isEmpty(itemText),"cannot be null");
return new TypeSafeMatcher<View>() {
@Override
protected boolean matchesSafely(View item) {
return allOf(isDescendantOfA(isAssignableFrom(RecyclerView.class)),withText(itemText)).matches(item);
}
@Override
public void describeTo(Description description) {
description.appendText("is descendant of a RecyclerView with text" + itemText);
}
};
}
`
Und dann mach das:
onView(withItemText("what")).perform(click());
Ich habe die Antwort von @ Gabor befolgt, aber als ich die Bibliotheken aufgenommen habe, habe ich das Dex-Limit erreicht!
Also entfernte ich die Bibliotheken, fügte diese getInstrumentation().waitForIdleSync();
hinzu und rief dann einfach onView(withId...))...
an.
Funktioniert perfekt.
In Ihrem Fall haben Sie mehrere Bildansichten mit derselben ID, so dass Sie etwas darüber herausfinden müssen, wie Sie den jeweiligen Listeneintrag auswählen können.
Sie müssen weder "testing-support-lib" noch "espresso: espresso-core" hinzufügen. Sie werden transitiv hinzugefügt, wenn "Espresso: Espresso-Contrib" hinzugefügt wird.
build.grade
dependencies {
androidTestCompile 'com.Android.support.test:runner:0.3'
androidTestCompile 'com.Android.support.test:rules:0.3'
androidTestCompile 'com.Android.support.test.espresso:espresso-contrib:2.2'
}
Verwendungszweck :
onView(withId(R.id.recyclerView)).perform(
RecyclerViewActions.actionOnItemAtPosition(0, click()));
Mit here können Sie Ihren benutzerdefinierten RecyclerView
-Matcher implementieren. Nehmen wir an, Sie haben RecyclerView
, wo jedes Element ein Thema hat, für das Sie keinen Treffer haben:
public static Matcher<RecyclerView.ViewHolder> withItemSubject(final String subject) {
Checks.checkNotNull(subject);
return new BoundedMatcher<RecyclerView.ViewHolder, MyCustomViewHolder>(
MyCustomViewHolder.class) {
@Override
protected boolean matchesSafely(MyCustomViewHolder viewHolder) {
TextView subjectTextView = (TextView)viewHolder.itemView.findViewById(R.id.subject_text_view_id);
return ((subject.equals(subjectTextView.getText().toString())
&& (subjectTextView.getVisibility() == View.VISIBLE)));
}
@Override
public void describeTo(Description description) {
description.appendText("item with subject: " + subject);
}
};
}
Und Verwendung:
onView(withId(R.id.my_recycler_view_id)
.perform(RecyclerViewActions.actionOnHolderItem(withItemSubject("My subject"), click()));
Grundsätzlich können Sie alles anpassen, was Sie möchten. In diesem Beispiel haben wir den Betreff TextView
verwendet, es kann sich jedoch um ein beliebiges Element im Element RecyclerView
handeln.
Eine weitere Sache zu klären ist die Überprüfung der Sichtbarkeit (subjectTextView.getVisibility() == View.VISIBLE)
. Wir müssen es haben, weil manchmal andere Ansichten in RecyclerView
dasselbe Thema haben können, aber es wäre mit View.GONE
. Auf diese Weise vermeiden wir mehrere Übereinstimmungen mit unserem benutzerdefinierten Matcher und einem Zielobjekt, das tatsächlich unser Thema anzeigt.