Les tests Espresso sont nouveaux pour moi, mais il ne semble pas qu'il soit possible de tester les modifications pouvant être effectuées.
J'ai un tutoriel qui s'appelle ImageView
Drawable
diaporama 'niché dans' un TextView
semi-transparent. Dans mes tests, je veux m'assurer que lorsque le bouton suivant est enfoncé, le Drawable
approprié a été inséré dans le ImageView
du tutoriel.
Il n'y a pas de nom par défaut Matcher
pour vérifier Drawable
name__s. Je me suis donc mis à écrire le mien en utilisant https://stackoverflow.com/a/28785178/981242 . Malheureusement, comme il n’existe aucun moyen de récupérer l’identifiant d’un ImageView
name __ actif Drawable
name__, je ne peux pas terminer l’implémentation matchesSafely()
.
Cela ne peut pas être le seul cas d'utilisation pour tester les Drawable
name__s actifs. Quel est l'outil que les gens utilisent normalement pour de telles situations?
Je préfère ne pas comparer les images bitmap et suivre les conseils de cette réponse: https://stackoverflow.com/a/14474954/1396068
Lorsque vous définissez le dessin de la vue d'image, stockez également l'ID pouvant être dessiné dans sa balise avec setTag(R.drawable.your_drawable)
. Ensuite, utilisez les adaptateurs withTagValue(equalTo(R.drawable.your_drawable))
de Espresso pour vérifier la balise correcte.
veuillez vérifier ce tutoriel que j'ai trouvé. semble fonctionner plutôt bien https://medium.com/@dbottillo/Android-ui-test-espresso-matcher-for-imageview-1a28c832626f#.4snjg8frw
Voici le résumé pour copier les pâtes ;-)
public class DrawableMatcher extends TypeSafeMatcher<View> {
private final int expectedId;
String resourceName;
public DrawableMatcher(int expectedId) {
super(View.class);
this.expectedId = expectedId;
}
@Override
protected boolean matchesSafely(View target) {
if (!(target instanceof ImageView)){
return false;
}
ImageView imageView = (ImageView) target;
if (expectedId < 0){
return imageView.getDrawable() == null;
}
Resources resources = target.getContext().getResources();
Drawable expectedDrawable = resources.getDrawable(expectedId);
resourceName = resources.getResourceEntryName(expectedId);
if (expectedDrawable == null) {
return false;
}
Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
Bitmap otherBitmap = ((BitmapDrawable) expectedDrawable).getBitmap();
return bitmap.sameAs(otherBitmap);
}
@Override
public void describeTo(Description description) {
description.appendText("with drawable from resource id: ");
description.appendValue(expectedId);
if (resourceName != null) {
description.appendText("[");
description.appendText(resourceName);
description.appendText("]");
}
}
}
Sachez que cela ne fonctionne que lorsque votre Drawable
est un BitmapDrawable
. Si vous avez également VectorDrawable
ou une autre Drawable
, vous devez vérifier cela (imageView.getDrawable() instanceOf XXXDrawable
) et en extraire le bitmap. Sauf que vous avez une sorte de dessin simple où vous avez seulement une couleur ou vous pouvez comparer.
Pour obtenir le bitmap d'un VectorDrawable, par exemple, vous devez dessiner le VectorDrawable sur un canevas et l'enregistrer dans un bitmap (j'ai eu quelques problèmes lorsque le VectorDrawable a été teinté). Si vous avez un StateListDrawable, vous pouvez obtenir le Drawable de l'état sélectionné et répéter votre cascade if .Of. Pour les autres types Drawable, je n'ai aucune expérience, désolé!
Il y a qu'un Gist qui contient withBackground()
, withCompoundDrawable()
, withImageDrawable()
matchers de Frankie Sardo . Tous les crédits à lui.
Et en ce qui concerne les identifiants d’image - vous pouvez taper R.drawable.image_name
, l’id du dessinable sera alors récupéré automatiquement.
Basé sur l'aide de @wolle et de @ FreewheelNat, pour comparer (Vector) Drawable:
public static Matcher<View> withDrawableId(@DrawableRes final int id) {
return new DrawableMatcher(id);
}
public static class DrawableMatcher extends TypeSafeMatcher<View> {
private final int expectedId;
private String resourceName;
public DrawableMatcher(@DrawableRes int expectedId) {
super(View.class);
this.expectedId = expectedId;
}
@Override
protected boolean matchesSafely(View target) {
if (!(target instanceof ImageView)) {
return false;
}
ImageView imageView = (ImageView) target;
if (expectedId < 0) {
return imageView.getDrawable() == null;
}
Resources resources = target.getContext().getResources();
Drawable expectedDrawable = resources.getDrawable(expectedId);
resourceName = resources.getResourceEntryName(expectedId);
if (expectedDrawable != null && expectedDrawable.getConstantState() != null) {
return expectedDrawable.getConstantState().equals(
imageView.getDrawable().getConstantState()
);
} else {
return false;
}
}
@Override
public void describeTo(Description description) {
description.appendText("with drawable from resource id: ");
description.appendValue(expectedId);
if (resourceName != null) {
description.appendText("[");
description.appendText(resourceName);
description.appendText("]");
}
}
}
J'accepte la réponse de @wolle comme valide, mais je voudrais admettre que, même pour Java, il pourrait même être plus simple que cela. Il peut être converti en un static function
(ou en une companion
dans Kotlin) et également nettoyer un code obsolète .
Quoi qu'il en soit, la solution pour Kotlin compactée par le code et non obsolète serait la suivante:
fun drawableIsCorrect(@DrawableRes drawableResId: Int): Matcher<View> {
return object : TypeSafeMatcher<View>() {
override fun describeTo(description: Description) {
description.appendText("with drawable from resource id: ")
description.appendValue(drawableResId)
}
override fun matchesSafely(target: View?): Boolean {
if (target !is ImageView) {
return false
}
if (drawableResId < 0) {
return target.drawable == null
}
val expectedDrawable = ContextCompat.getDrawable(target.context, drawableResId)
?: return false
val bitmap = (target.drawable as BitmapDrawable).bitmap
val otherBitmap = (expectedDrawable as BitmapDrawable).bitmap
return bitmap.sameAs(otherBitmap)
}
}
}
22 lignes contre 44, hein?
J'ai déjà répondu sur le même sujet ici: Obtenir l'ID d'un dessinable dans ImageView . L'approche consiste à marquer une vue avec un identifiant de ressource spécifié dans la variable personnalisée LayoutInflater
. L'ensemble du processus est automatisé par une simple bibliothèque TagView . C'est particulièrement utile pour le test Espresso car il n'est pas nécessaire de baliser manuellement toutes les vues de votre projet. En fait, vous n'avez rien à changer, sauf que vous définissez des éléments dessinables au moment de l'exécution. Dans ce cas, vous devez examiner Tagging in runtime section.
En conséquence, vous pouvez comparer deux drawables uniquement par leurs identifiants:
onView(withId(R.id.imageview)).check(assertTagKeyValue(
ViewTag.IMAGEVIEW_SRC.id, Android.R.drawable.ic_media_play));
L'assertion Espresso personnalisée assertTagKeyValue
est disponible ici