Vérification du message de pain grillé dans un espresso Android

Quelqu’un pourrait-il savoir comment tester l’apparition d’un message Toast dans un espresso Android? En robotium, c’est facile et j’ai commencé à travailler en espresso, mais je n’ai pas reçu la commande exacte.

Cette déclaration légèrement longue fonctionne pour moi:

import static android.support.test.espresso.assertion.ViewAssertions.matches; import static android.support.test.espresso.matcher.RootMatchers.withDecorView; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; .... onView(withText(R.ssortingng.TOAST_STRING)).inRoot(withDecorView(not(is(getActivity().getWindow().getDecorView())))).check(matches(isDisplayed())); 

La réponse acceptée est bonne mais n’a pas fonctionné pour moi. J’ai donc cherché un peu et trouvé cet article de blog . Cela m’a donné une idée de la façon de le faire et j’ai mis à jour la solution ci-dessus.

J’ai d’abord implémenté le ToastMatcher:

 import android.os.IBinder; import android.support.test.espresso.Root; import android.view.WindowManager; import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; public class ToastMatcher extends TypeSafeMatcher { @Override public void describeTo(Description description) { description.appendText("is toast"); } @Override public boolean matchesSafely(Root root) { int type = root.getWindowLayoutParams().get().type; if (type == WindowManager.LayoutParams.TYPE_TOAST) { IBinder windowToken = root.getDecorView().getWindowToken(); IBinder appToken = root.getDecorView().getApplicationWindowToken(); if (windowToken == appToken) { // windowToken == appToken means this window isn't contained by any other windows. // if it was a window for an activity, it would have TYPE_BASE_APPLICATION. return true; } } return false; } } 

Ensuite, j’ai implémenté mes méthodes de vérification comme ceci:

 public void isToastMessageDisplayed(int textId) { onView(withText(textId)).inRoot(MobileViewMatchers.isToast()).check(matches(isDisplayed())); } 

MobileViewMatchers est un conteneur pour accéder aux matchers. Là j’ai défini la méthode statique isToast() .

 public static Matcher isToast() { return new ToastMatcher(); } 

Cela fonctionne comme un charme pour moi.

Assurez-vous d’abord d’importer:

 import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.matcher.ViewMatchers.withText; import static android.support.test.espresso.matcher.RootMatchers.withDecorView; import static android.support.test.espresso.assertion.ViewAssertions.matches; 

Dans votre classe, vous avez probablement une règle comme celle-ci:

 @Rule public ActivityTestRule activityTestRule = new ActivityTestRule<>(MyNameActivity.class); 

Dans votre test:

 MyNameActivity activity = activityTestRule.getActivity(); onView(withText(R.ssortingng.toast_text)). inRoot(withDecorView(not(is(activity.getWindow().getDecorView())))). check(matches(isDisplayed())); 

Cela a fonctionné pour moi, et c’était assez facile à utiliser.

Commencez par créer un object Toast Matcher que nous pouvons utiliser dans nos cas de test –

 public class ToastMatcher extends TypeSafeMatcher { @Override public void describeTo(Description description) { description.appendText("is toast"); } @Override public boolean matchesSafely(Root root) { int type = root.getWindowLayoutParams().get().type; if ((type == WindowManager.LayoutParams.TYPE_TOAST)) { IBinder windowToken = root.getDecorView().getWindowToken(); IBinder appToken = root.getDecorView().getApplicationWindowToken(); if (windowToken == appToken) { //means this window isn't contained by any other windows. } } return false; } 

1. Testez si le message Toast est affiché

 onView(withText(R.ssortingng.mssage)).inRoot(new ToastMatcher()) .check(matches(isDisplayed())); 

2. Tester si le message Toast n’est pas affiché

 onView(withText(R.ssortingng.mssage)).inRoot(new ToastMatcher()) .check(matches(not(isDisplayed()))); 

3. Tester que le Toast contient un message texte spécifique

 onView(withText(R.ssortingng.mssage)).inRoot(new ToastMatcher()) .check(matches(withText("Invalid Name")); 

Merci Anuja

Note – cette réponse provient de This POST.

Bien que la question ait une réponse acceptée – ce que BTW ne fonctionne pas pour moi – j’aimerais append ma solution dans Kotlin, que je tire de la réponse de Thomas R.:

 package somepkg import android.support.test.espresso.Espresso.onView import android.support.test.espresso.Root import android.support.test.espresso.matcher.ViewMatchers.withText import android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY import android.view.WindowManager.LayoutParams.TYPE_TOAST import org.hamcrest.Description import org.hamcrest.Matcher import org.hamcrest.TypeSafeMatcher /** * This class allows to match Toast messages in tests with Espresso. * * Idea taken from: https://stackoverflow.com/a/33387980 * * Usage in test class: * * import somepkg.ToastMatcher.Companion.onToast * * // To assert a toast does *not* pop up: * onToast("text").check(doesNotExist()) * onToast(textId).check(doesNotExist()) * * // To assert a toast does pop up: * onToast("text").check(matches(isDisplayed())) * onToast(textId).check(matches(isDisplayed())) */ class ToastMatcher(private val maxFailures: Int = DEFAULT_MAX_FAILURES) : TypeSafeMatcher() { /** Ressortingct number of false results from matchesSafely to avoid endless loop */ private var failures = 0 override fun describeTo(description: Description) { description.appendText("is toast") } public override fun matchesSafely(root: Root): Boolean { val type = root.windowLayoutParams.get().type @Suppress("DEPRECATION") // TYPE_TOAST is deprecated in favor of TYPE_APPLICATION_OVERLAY if (type == TYPE_TOAST || type == TYPE_APPLICATION_OVERLAY) { val windowToken = root.decorView.windowToken val appToken = root.decorView.applicationWindowToken if (windowToken === appToken) { // windowToken == appToken means this window isn't contained by any other windows. // if it was a window for an activity, it would have TYPE_BASE_APPLICATION. return true } } // Method is called again if false is returned which is useful because a toast may take some time to pop up. But for // obvious reasons an infinite wait isn't of help. So false is only returned as often as maxFailures specifies. return (++failures >= maxFailures) } companion object { /** Default for maximum number of resortinges to wait for the toast to pop up */ private const val DEFAULT_MAX_FAILURES = 5 fun onToast(text: Ssortingng, maxResortinges: Int = DEFAULT_MAX_FAILURES) = onView(withText(text)).inRoot(isToast(maxResortinges))!! fun onToast(textId: Int, maxResortinges: Int = DEFAULT_MAX_FAILURES) = onView(withText(textId)).inRoot(isToast(maxResortinges))!! fun isToast(maxResortinges: Int = DEFAULT_MAX_FAILURES): Matcher { return ToastMatcher(maxResortinges) } } } 

J’espère que cela aidera les lecteurs ultérieurs – l’utilisation est décrite dans le commentaire.

Je dirais que pour les messages de pain grillé définir d’abord votre règle

  @Rule public ActivityTestRule activityTestRule = new ActivityTestRule<>(AuthActivity.class); 

alors quel que soit le texte du message que vous recherchez, tapez-le entre guillemets, par exemple, j’ai utilisé “adresse email invalide”

  onView(withText("Invalid email address")) .inRoot(withDecorView(not(activityTestRule.getActivity().getWindow().getDecorView()))) .check(matches(isDisplayed())); 

La façon dont Toasts sont implémentés permet de détecter qu’un toast a été affiché. Cependant, il n’y a aucun moyen de voir si un toast a été demandé, par un appel à show ()) ou de bloquer entre la période entre show () et le moment où le toast est devenu visible. Cela ouvre des problèmes de timing insolubles (que vous ne pouvez résoudre que par le biais du sumil et de l’espoir).

Si vous voulez vraiment vérifier ceci, voici une alternative pas très jolie utilisant Mockito et un espion de test:

 public interface Toaster { public void showToast(Toast t); private static class RealToaster { @Override public void showToast(Toast t) { t.show(); } public static Toaster makeToaster() { return new RealToaster(); } } Then in your test public void testMyThing() { Toaster spyToaster = Mockito.spy(Toaster.makeToaster()); getActivity().setToaster(spyToaster); onView(withId(R.button)).perform(click()); getInstrumentation().runOnMainSync(new Runnable() { @Override public void run() { // must do this on the main thread because the matcher will be interrogating a view... Mockito.verify(spyToaster).showToast(allOf(withDuration(Toast.LENGTH_SHORT), withView(withText("hello world")); }); } // create a matcher that calls getDuration() on the toast object Matcher withDuration(int) // create a matcher that calls getView() and applies the given view matcher Matcher withView(Matcher viewMatcher) another answer regarding this if(someToast == null) someToast = Toast.makeText(this, "sdfdsf", Toast.LENGTH_LONG); boolean isShown = someToast.getView().isShown();