web-dev-qa-db-ja.com

Android espressoでトーストメッセージを確認する

Android espressoでToastメッセージの外観をテストする方法を知っている人はいますか?robotiumでは簡単です。

63
Humayun Rana

このわずかに長い文は私にとってはうまくいきます:

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()));
105
kowalcj0

受け入れられた答えは良いものですが、私にとってはうまくいきませんでした。そこで、少し検索して このブログ記事 を見つけました。これにより、その方法のアイデアが得られ、上記のソリューションを更新しました。

まず、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<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;
  }

}
_

次に、次のようなチェックメソッドを実装しました。

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

MobileViewMatchersは、マッチャーにアクセスするためのコンテナーです。そこで、静的メソッドisToast()を定義しました。

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

これは私にとって魅力的です。

43
Thomas R.

最初にインポートすることを確認してください:

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;

クラス内には、おそらく次のようなルールがあります。

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

テスト内:

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

これは私のために働いた、そしてそれは非常に使いやすかった。

12
lmiguelvargasf

質問には受け入れられた答えがありますが、BTWは私にはうまくいきませんが、トーマス・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<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)
        }
    }

}

これが後の読者の助けになることを願っています-使用法はコメントに記載されています。

3
yasd

最初に、テストケースで使用できるカスタムトーストマッチャーを作成します-

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

1。トーストメッセージが表示されるかどうかをテストします

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

2。トーストメッセージが表示されないかどうかをテストします

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

3。 Toastに特定のテキストメッセージが含まれているテストID

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

ありがとう、アヌジャ

注-この回答は This POST。

3
anuja jain

最新のAndroid Testing Tools from Jetpackを使用している場合、ActivityTestRuleは非推奨であり、ActivityScenarioまたはActivityScenarioRule(最初のものを含む)を使用する必要があります。

前提条件。 decorView変数を作成し、テストの前に割り当てます。

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

自身をテストする

@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()androidx.test.core.app.ApplicationProvider.getApplicationContext;

0
Akbolat SSS

トーストメッセージの場合、最初にルールを定義します

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

次に、探しているトーストメッセージテキストを引用の間に入力します。たとえば、「無効なメールアドレス」を使用しました

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

カスタムトーストマッチャーを作成します。

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

そして、次のように使用します:

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

私はこれにかなり慣れていますが、すべてのアクション(スワイプ、クリックなど)と検証(コンテンツのテキストビューのチェックなど)をすべて含む基本クラス「BaseTest」を作成しました。

protected fun verifyToastMessageWithText(text: String, activityTestRule: ActivityTestRule<*>) {
        onView(withText(text)).inRoot(withDecorView(not(activityTestRule.activity.window.decorView))).check(matches(isDisplayed()))
    }

protected fun verifyToastMessageWithStringResource(id: Int, activityTestRule: ActivityTestRule<*>) {
        onView(withText(id)).inRoot(withDecorView(not(activityTestRule.activity.window.decorView))).check(matches(isDisplayed()))
    }
0
user1791622