Android – expresso – cliquant sur une entrée de liste basée sur des objets personnalisés

Espresso est utilisé pour tester automatiquement mon application.

Édition: ci-dessous, vous trouvez un certain nombre de réponses!

  • Comment détruire les anciens fragments dans FragmentStatePagerAdapter
  • Comment centrer les articles d'un recyclage?
  • Bibliothèque de support Android SearchView xml attributes queryHint et iconifiedByDefault ne fonctionne pas
  • Gradle: FAILURE: Impossible de déterminer les tâches à exécuter
  • Comment obtenir le nom de classe, pas le chemin complet?
  • Comment convertir string Date en mills-secondes longues
  • Comment puis-je cliquer (dans un script de test Espresso automatisé) sur une entrée dans une longue liste d'objets personnalisés?

    Dans la documentation Espresso, il existe un exemple de LongList. Travailler avec une liste d'objets est ce que je fais normalement. En essayant de nombreuses options pour passer de la carte à l'objet n'a pas donné de bons résultats jusqu'à présent.

    La documentation d'Espresso indique qu'un 'onData' devrait être utilisé. Donc, quelque chose comme:

    onData( myObjectHasContent("my_item: 50")).perform(click()); onView(withId( R.id.selection_pos2)).check(matches(withText("50"))); 

    Mes questions (et je pense qu'elles sont utiles pour la communauté d'apprentissage): – Pouvez-vous écrire un bon Matcher pour cela? – Comment pouvons-nous l'utiliser dans 'onData'?

    Quelle est la situation? À l'écran, j'ai une liste d'objets comme:

     public class MyOjbect { public String content; public int size; } 

    L'adaptateur que j'utilise pour remplir la liste peuplée est:

     public class MyObjectWithItemAndSizeAdapter extends ArrayAdapter<MyObjectWithItemAndSize> { private final Context context; private final List<MyObjectWithItemAndSize> values; ... @Override public View getView(int position, View concertView, ViewGroup parent) { View view = null; if (concertView != null) { view = (LinearLayout) concertView; } else { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate( R.layout.list_item, parent, false); } TextView itemT = (TextView) view.findViewById( R.id.item_content); itemT.setText( values.get(position).item); TextView sizeT = (TextView) view.findViewById( R.id.item_size); sizeT.setText( "" + values.get(position).size); return view; } } 

  • Mémoire insuffisante lors de l'allocation de curseurs
  • Comment désactiver l'effondrement d'une ExpandableListView?
  • Comment puis-je diviser une chaîne par rupture de ligne?
  • Existe-t-il un moyen de forcer Google Speech api à renvoyer uniquement les mots comme réponse?
  • SeekBar et lecteur multimédia dans Android
  • Comment définir setOnClickListener pour AutoCompleteTextView?
  • 3 Solutions collect form web for “Android – expresso – cliquant sur une entrée de liste basée sur des objets personnalisés”

    Le matcher donné à onData() doit correspondre à la valeur souhaitée renvoyée par Adapter.getItem(int) de ListView souhaité.

    Donc dans votre exemple, le matcher devrait être quelque chose comme ceci:

     public static Matcher<Object> withContent(final String content) { return new BoundedMatcher<Object, MyObjectWithItemAndSize>(MyObjectWithItemAndSize.class) { @Override public boolean matchesSafely(MyObjectWithItemAndSize myObj) { return myObj.content.equals(content); } @Override public void describeTo(Description description) { description.appendText("with content '" + content + "'"); } }; } 

    Une addition à la réponse précédente, je crée une version complète avec 2 types de validations. Cela peut vous aider à comprendre Espresso et Custom Matchers.

    La différence avec l'exemple standard de Espresso LongList est que j'utilise une liste d'objets personnalisés à afficher dans une liste. Faire défiler vers la droite liste-entrée et vérifier le résultat est montré ci-dessous.

    Méthode 1 – la validation contre une chaîne

    Dans le script de test est:

     onData( allOf( instanceOf( MyObjectWithItemAndSize.class), myCustomObjectShouldHaveString( "my_item: 60"))) .perform(click()); // testing the result ... as in the longlist example onView(withId(R.id.selection_pos2)).check(matches(withText("my_item: 60"))); 

    Le matcher est:

     public static Matcher<Object> myCustomObjectShouldHaveString( String expectedTest) { return myCustomObjectShouldHaveString( equalTo( expectedTest)); } private static Matcher<Object> myCustomObjectShouldHaveString(final Matcher<String> expectedObject) { return new BoundedMatcher<Object, MyObjectWithItemAndSize>( MyObjectWithItemAndSize.class) { @Override public boolean matchesSafely(final MyObjectWithItemAndSize actualObject) { // next line is important ... requiring a String having an "equals" method if( expectedObject.matches( actualObject.item) ) { return true; } else { return false; } } @Override public void describeTo(final Description description) { // could be improved, of course description.appendText("getnumber should return "); } }; } 

    Méthode 2: validation contre l'objet (objet complet).

    Dans le script de test, vous trouvez:

     MyObjectWithItemAndSize myObject = new MyObjectWithItemAndSize( "my_item: 60", 11); onData( allOf( instanceOf( MyObjectWithItemAndSize.class), myObjectHasContent( myObject))).perform( click()); onView(withId( R.id.selection_pos2)).check(matches(withText("my_item: 60"))); 

    Le matcher est.

    La ligne la plus importante (j'ai eu des difficultés avec) est en dessous de // ****

     public static Matcher<Object> myObjectHasContent( MyObjectWithItemAndSize expectedObject) { return myObjectHasContent( equalTo( expectedObject)); } //private method that does the work of matching private static Matcher<Object> myObjectHasContent(final Matcher<MyObjectWithItemAndSize> expectedObject) { return new BoundedMatcher<Object, MyObjectWithItemAndSize>(MyObjectWithItemAndSize.class) { @Override public boolean matchesSafely( final MyObjectWithItemAndSize actualObject) { // ****** ... the 'matches'. See below. // this requires the MyObjectWithItemAndSize to have an 'equals' method if( expectedObject.matches( actualObject) ) { return true; } else { return false; } } @Override public void describeTo(final Description description) { description.appendText("getnumber should return "); } }; } 

    Ce qui est très important, c'est que l'objet personnalisé a cette méthode (et je supposer que je suis renversé):

     @Override public boolean equals( Object mob2) { return( (this.item.equals( ((MyObjectWithItemAndSize) mob2).item))); // of course, could have also a check on this.size. } 

    Et il fonctionne!!!! Pfff, a pris un certain temps, mais a surmonté. Merci aussi à Yash F.

    J'ai dû tester et AdapterView avec un adaptateur personnalisé utilisant Espresso 2 aujourd'hui. J'ai fini par utiliser FeatureMatcher:

     private static FeatureMatcher<Product, String> withProductName(final String productName) { return new FeatureMatcher<Product, String>(equalTo(productName), "with productName", "productName") { @Override protected String featureValueOf(Product actual) { return actual.name; } }; } 

    Et puis appeler cette méthode d'utilité à partir d'un test comme suit:

     onData(withProductName("My Awesome Product")) .inAdapterView(withId(R.id.product_list)) .onChildView(withId(R.id.product_title)) .check(matches(withText("My Awesome Product"))); 

    Je pense que FeatureMatcher est génial lorsque vous souhaitez affirmer une propriété spécifique d'un objet de données.

    coAndroid est un fan Android de Google, tout sur les téléphones Android, Android Wear, Android Dev et Android Games Apps.