Überprüfen der Toastnachricht in Android Espresso

Lesezeit: 9 Minuten

Uberprufen der Toastnachricht in Android Espresso
Humayun Rana

Würde jemand wissen, wie man das Erscheinen einer Toast-Nachricht in Android Espresso testet? In Robotium ist es einfach und ich habe es verwendet, aber angefangen, in Espresso zu arbeiten, aber ich bekomme nicht den genauen Befehl.

  • Keine der folgenden Lösungen funktioniert, wenn die Aktivität zur selben Zeit beendet wird, zu der der Toast angezeigt wird.

    – Slawisch

    1. Dezember 17 um 9:47 Uhr

  • @Slav hast du eine Lösung gefunden, die die Toast-Überprüfung auch dann beinhaltet, wenn die Aktivität beendet ist?

    – NixSam

    5. Dezember 18 um 10:14 Uhr

  • @NixSam Leider nicht. Wenn ich mich richtig erinnere, habe ich mich beim Beenden der Aktivität darauf festgelegt, zu überprüfen, ob die Aktivität beendet wird.

    – Slawisch

    5. Dezember 18 um 10:56 Uhr

  • @Slav Danke für die Info

    – NixSam

    5. Dezember 18 um 14:32 Uhr

Diese etwas lange Aussage funktioniert für mich:

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.string.TOAST_STRING)).inRoot(withDecorView(not(is(getActivity().getWindow().getDecorView())))).check(matches(isDisplayed()));

  • is() Methode ist überflüssig

    – Slava

    10. April 15 um 20:43 Uhr

  • @Slava ist richtig, es kann durch Entfernen von is: onView(withText(R.string.TOAST_STRING)).inRoot(withDecorView(not(getActivity().getWindow().getDecorView()))) .check(matches( wird angezeigt()));

    – Bindung

    20. April 15 um 18:03 Uhr


  • Methode getActivity() kann nicht aufgelöst werden. Fehler, wie dies zu lösen ist

    – John

    16. Juli 15 um 13:30 Uhr

  • @John: Du verwendest wahrscheinlich das Neue Regelbasierte JUnit-Tests mit einem ActivityTestRule. Sie können die Aktivität aus dieser Regel mit abrufen ActivityTestRule#getActivity().

    – Leo Nikkilä

    29. August 15 um 18:20 Uhr

  • Mit ActivityTestRule: onView(withText(R.string.toast_text)).inRoot(withDecorView(not(mActivityRule.getActivity().getWindow().getDecorView()))).check(matches(isDisplayed()));

    – StefanTo

    8. Dezember 15 um 14:29 Uhr


Uberprufen der Toastnachricht in Android Espresso
Thomas R.

Die akzeptierte Antwort ist gut, hat aber bei mir nicht funktioniert. Also habe ich ein bisschen gesucht und gefunden diesen Blogartikel. Dies gab mir eine Vorstellung davon, wie es geht, und ich habe die obige Lösung aktualisiert.

Zuerst habe ich den ToastMatcher implementiert:

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<Root> {

  @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;
  }

}

Dann habe ich meine Prüfmethoden wie folgt implementiert:

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

MobileViewMatchers ist ein Container für den Zugriff auf die Matcher. Dort habe ich die statische Methode definiert isToast().

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

Das funktioniert wie ein Zauber für mich.

  • Dies funktioniert bei mir nicht, da der Test ständig wiederholt wird. Das einzige, was funktioniert, ist, wenn ich den Bildschirm berühre, während der Toast geöffnet ist, scheint er den Leerlauf zu stoppen und funktioniert dann. Irgendwelche Ideen?

    – AdamMc331

    6. September 16 um 18:16 Uhr


  • Ich muss Ihren Testaufbau kennen. Was möchten Sie testen und was wird angezeigt? Klingt nach einem Fortschrittsproblem, stackoverflow.com/questions/33289152/progressbars-and-espresso/…. Tritt das bei allen API-Versionen auf?

    –Thomas R.

    7. September 16 um 6:36 Uhr

  • Woher kommt “MobileViewMatchers”? Es kann nicht importiert oder im Code gefunden werden

    – HRVHacker

    22. September 16 um 22:05 Uhr

  • WindowManager.LayoutParams.TYPE_TOAST ist jetzt veraltet.

    – makowkastar

    14. November 17 um 15:07 Uhr

  • Ich kann Toastnachrichten mit diesem Code nur validieren, wenn Toast auf dem Bildschirm angezeigt wird. Aber wenn es eine Bedingung mit folgenden Ergebnissen gibt: a) msg1 b) msg2 c) Überhaupt kein Toast. Dann werden die Optionen a und b validiert, aber der Code bleibt in Option c hängen. Was kann eine mögliche Lösung für dasselbe sein?

    – Tiefentief Singh

    12. Februar 18 um 6:18 Uhr


1643858588 706 Uberprufen der Toastnachricht in Android Espresso
lmiguelvargasf

Stellen Sie zunächst sicher, dass Sie Folgendes importieren:

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;

In Ihrer Klasse haben Sie wahrscheinlich eine Regel wie diese:

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

In Ihrem Test:

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

Das funktionierte für mich, und es war ziemlich einfach zu bedienen.

  • Nur eine Anmerkung: Dieser Ansatz (und die meisten anderen Antworten) funktionieren bei Verwendung von Android 11 API 30 nicht "targetSdkVersion 30" und "compileSdkVersion 30". Sehen: github.com/android/android-test/issues/803

    – Herr-IDE

    8. September 21 um 15:32 Uhr

1643858588 321 Uberprufen der Toastnachricht in Android Espresso
Akbolat SSS

Wenn Sie die neueste verwenden Android-Testtools von JetpackDu weißt, dass ActivityTestRule ist veraltet und sollte verwendet werden ActivityScenario oder ActivityScenarioRule(welches das erste enthält).

Voraussetzungen. decorView-Variable erstellen und vor Tests zuweisen;

@Rule
public ActivityScenarioRule<FeedActivity> activityScenarioRule = new ActivityScenarioRule<>(FeedActivity.class);

private View decorView;

@Before
public void setUp() {
    activityScenarioRule.getScenario().onActivity(new ActivityScenario.ActivityAction<FeedActivity>() {
        @Override
        public void perform(FeedActivityactivity) {
            decorView = activity.getWindow().getDecorView();
        }
    });
}

Selbst testen

@Test
public void given_when_thenShouldShowToast() {
    String expectedWarning = getApplicationContext().getString(R.string.error_empty_list);
    onView(withId(R.id.button))
            .perform(click());

    onView(withText(expectedWarning))
            .inRoot(withDecorView(not(decorView)))// Here we use decorView
            .check(matches(isDisplayed()));
}

getApplicationContext() entnommen werden können androidx.test.core.app.ApplicationProvider.getApplicationContext;

1643858588 874 Uberprufen der Toastnachricht in Android Espresso
anuja jain

Erstellen Sie zuerst einen benutzerdefinierten Toast Matcher, den wir in unseren Testfällen verwenden können –

public class ToastMatcher extends TypeSafeMatcher<Root> {
    
        @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 true;
                }
            }
            return false;
        }
}

1. Testen Sie, ob die Toast-Meldung angezeigt wird

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

2. Testen Sie, ob die Toast-Meldung nicht angezeigt wird

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

3. Testen Sie, ob der Toast eine bestimmte Textnachricht enthält

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

Danke, Anuja

Hinweis – diese Antwort ist von Dieser Beitrag.

  • Es sollte sein: if (windowToken == appToken) { //bedeutet, dass dieses Fenster nicht in anderen Fenstern enthalten ist. gib true zurück; }

    – Akshay Mahajan

    10. Februar 17 um 9:55 Uhr

  • @anuja jain Wenn die Antwort von stackoverflow.com/a/40756080/5230044 funktioniert, warum sollten wir dann auf Ihre Antwort verweisen

    – cammando

    1. April 17 um 17:23 Uhr

  • wie im ursprünglichen Beitrag in den Kommentaren erwähnt, funktioniert dies NICHT. Es schlägt mit einer Ausnahme fehl. Auch in diesem Beitrag fehlt die Rückkehr wahr; nach dem Kommentar, wenn die Token übereinstimmen, also wird es auch nicht funktionieren.

    – Benutzer330844

    6. September 17 um 16:14 Uhr

  • Root ist nicht Teil der öffentlichen API.

    – Rabyunghwa

    23. Juli 21 um 5:00 Uhr

  • Tolle Antwort, dies sollte die akzeptierte sein

    – edv

    7. September 21 um 14:13 Uhr

1643858589 203 Uberprufen der Toastnachricht in Android Espresso
jasd

Obwohl die Frage eine akzeptierte Antwort hat – die übrigens für mich nicht funktioniert – möchte ich meine Lösung in Kotlin hinzufügen, die ich aus der Antwort von Thomas R. abgeleitet habe:

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<Root>() {

    /** Restrict 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 retries to wait for the toast to pop up */
        private const val DEFAULT_MAX_FAILURES = 5

        fun onToast(text: String, maxRetries: Int = DEFAULT_MAX_FAILURES) = onView(withText(text)).inRoot(isToast(maxRetries))!!

        fun onToast(textId: Int, maxRetries: Int = DEFAULT_MAX_FAILURES) = onView(withText(textId)).inRoot(isToast(maxRetries))!!

        fun isToast(maxRetries: Int = DEFAULT_MAX_FAILURES): Matcher<Root> {
            return ToastMatcher(maxRetries)
        }
    }

}

Ich hoffe, dass dies für spätere Leser hilfreich ist – die Verwendung wird im Kommentar beschrieben.

  • Es sollte sein: if (windowToken == appToken) { //bedeutet, dass dieses Fenster nicht in anderen Fenstern enthalten ist. gib true zurück; }

    – Akshay Mahajan

    10. Februar 17 um 9:55 Uhr

  • @anuja jain Wenn die Antwort von stackoverflow.com/a/40756080/5230044 funktioniert, warum sollten wir dann auf Ihre Antwort verweisen

    – cammando

    1. April 17 um 17:23 Uhr

  • wie im ursprünglichen Beitrag in den Kommentaren erwähnt, funktioniert dies NICHT. Es schlägt mit einer Ausnahme fehl. Auch in diesem Beitrag fehlt die Rückkehr wahr; nach dem Kommentar, wenn die Token übereinstimmen, also wird es auch nicht funktionieren.

    – Benutzer330844

    6. September 17 um 16:14 Uhr

  • Root ist nicht Teil der öffentlichen API.

    – Rabyunghwa

    23. Juli 21 um 5:00 Uhr

  • Tolle Antwort, dies sollte die akzeptierte sein

    – edv

    7. September 21 um 14:13 Uhr

Uberprufen der Toastnachricht in Android Espresso
Alexej

Ich schreibe meinen benutzerdefinierten Toast-Matcher:

import android.view.WindowManager
import androidx.test.espresso.Root
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
class ToastMatcher : TypeSafeMatcher<Root>() {

    override fun describeTo(description: Description) {
        description.appendText("is toast")
    }

    override fun matchesSafely(root: Root): Boolean {
        val type = root.getWindowLayoutParams().get().type
        if (type == WindowManager.LayoutParams.TYPE_TOAST) {
            val windowToken = root.getDecorView().getWindowToken()
            val appToken = root.getDecorView().getApplicationWindowToken()
            if (windowToken === appToken) {
                return true
            }
        }
        return false
    }
}

Und so verwenden:

onView(withText(R.string.please_input_all_fields)).inRoot(ToastMatcher()).check(matches(isDisplayed()))

.

749890cookie-checkÜberprüfen der Toastnachricht in Android Espresso

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy