J'ai un RecyclerView (R.id.recyclerView) où chaque ligne a une image (R.id.row_image) et un TextView. Je veux cliquer sur l'image dans la première rangée.
J'ai essayé d'utiliser onData (..) mais cela ne semble pas fonctionner.
Utilisez RecyclerViewActions
onView(withId(R.id.recyclerView))
.perform(actionOnItemAtPosition(0, click()));
Incluez ceci dans votre script gradle:
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'
}
Juste pour ajouter à la réponse de Gabor (qui est la réponse correcte et complète depuis Espresso 2.0).
Vous pouvez rencontrer des problèmes au moment de l’utilisation de espresso-contrib
et RecyclerView
s (voir Ticket Android-test-kit ).
Une solution de contournement consiste à ajouter cette exclusion dans la dépendance espresso-contrib
Gabor mentionnée ci-dessus:
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'
}
(Ceci est une réponse au lieu d'un commentaire sur la réponse de Gabor car je n'ai pas encore le droit de poster des commentaires)
Espresso 2.0 est sorti, le changelog comprend les éléments suivants:
Nouvelles fonctionnalités
- espresso-contrib
- RecyclerViewActions: gère les interactions avec RecyclerViews
Je n'ai pas encore testé cela moi-même, mais Thomas Keller a posté ceci sur G + avec une brève explication et un lien vers un Gist avec les points de vue nécessaires.
Étant donné que la nouvelle API
RecyclerView
hérite deViewGroup
et non deAdapterView
, vous ne pouvez pas utiliser la fonctiononData()
de Espresso pour tester les dispositions à l'aide de ce composant.
Je vais attacher le code, juste pour être complet (note: pas le mien! Tout le mérite revient à 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));
}
}
Et exemple d'utilisation:
onRecyclerItemView(R.id.item_title, withText("Test"), withId(R.id.item_content))
.matches(check(withText("Test Content")));
Vous devez utiliser un ViewAction personnalisé:
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));
}
}
J'ai suivi la réponse de @Gabor mais quand j'ai inclus les bibliothèques, je ai atteint la limite de dex!
J'ai donc supprimé les bibliothèques, ajouté cette getInstrumentation().waitForIdleSync();
et juste appelé onView(withId...))...
Marche parfaitement.
Dans votre cas, vous aurez plusieurs vues d’image avec le même identifiant. Vous devrez donc trouver un moyen de sélectionner un élément de la liste.
Vous n'avez pas besoin d'ajouter "testing-support-lib", ni "espresso: expresso-core". Ils sont ajoutés à la suite de l'expression "espresso: espresso-contrib".
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'
}
Utilisation :
onView(withId(R.id.recyclerView)).perform(
RecyclerViewActions.actionOnItemAtPosition(0, click()));
Comme je l'ai posté ici vous pouvez implémenter votre correcteur RecyclerView
personnalisé. Supposons que vous ayez RecyclerView
où chaque élément a le même sujet que vous voulez apparier:
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);
}
};
}
Et utilisation:
onView(withId(R.id.my_recycler_view_id)
.perform(RecyclerViewActions.actionOnHolderItem(withItemSubject("My subject"), click()));
Fondamentalement, vous pouvez faire correspondre tout ce que vous voulez. Dans cet exemple, nous avons utilisé le sujet TextView
mais il peut s'agir de n'importe quel élément de l'élément RecyclerView
.
Une dernière chose à clarifier est de vérifier la visibilité (subjectTextView.getVisibility() == View.VISIBLE)
. Nous avons besoin de l'avoir parce que parfois d'autres vues dans RecyclerView
peuvent avoir le même sujet mais ce serait avec View.GONE
. De cette façon, nous évitons les correspondances multiples de notre élément de correspondance personnalisé et de l'élément cible uniquement qui affiche réellement notre sujet.