Android Espresso:如何检查Toast消息是否未显示?

And*_*der 7 testing android functional-testing android-espresso

我现在正在进行功能测试,其中一个我必须测试没有显示吐司信息.考虑到这是我用来检查是否显示toast消息的代码(此代码有效):

onView(withText(R.string.my_toast_message))
        .inRoot(withDecorView(not(getActivity().getWindow().getDecorView())))
        .check(matches(isDisplayed()));
Run Code Online (Sandbox Code Playgroud)

下面你可以找到我用来检查没有显示吐司信息的代码(它们都不起作用):

方法一:

onView(withText(R.string.error_invalid_login))
        .inRoot(withDecorView(not(getActivity().getWindow().getDecorView())))
        .check(matches(not(isDisplayed())));
Run Code Online (Sandbox Code Playgroud)

方法二:

onView(withText(R.string.error_invalid_login))
        .inRoot(withDecorView(not(getActivity().getWindow().getDecorView())))
        .check(doesNotExist());
Run Code Online (Sandbox Code Playgroud)

任何关于如何检查未显示吐司信息的想法都会非常感激:)

TWi*_*Rob 6

需要捕获toast不存在的情况,为此NoMatchingRootException抛出a。下面显示了捕捉它的“浓缩咖啡方式”。

public static Matcher<Root> isToast() {
    return new WindowManagerLayoutParamTypeMatcher("is toast", WindowManager.LayoutParams.TYPE_TOAST);
}
public static void assertNoToastIsDisplayed() {
    onView(isRoot())
            .inRoot(isToast())
            .withFailureHandler(new PassMissingRoot())
            .check(matches(not(anything("toast root existed"))))
    ;
}
Run Code Online (Sandbox Code Playgroud)

使用上述内容的快速(自我)测试:

@Test public void testToastMessage() {
    Toast toast = createToast("Hello Toast!");
    assertNoToastIsDisplayed();
    toast.show();
    onView(withId(android.R.id.message))
            .inRoot(isToast())
            .check(matches(withText(containsStringIgnoringCase("hello"))));
    toast.cancel();
    assertNoToastIsDisplayed();
}

private Toast createToast(final String message) {
    final AtomicReference<Toast> toast = new AtomicReference<>();
    InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
        @SuppressLint("ShowToast") // will be shown later
        @Override public void run() {
            toast.set(Toast.makeText(InstrumentationRegistry.getContext(), message, Toast.LENGTH_LONG));
        }
    });
    return toast.get();
}
Run Code Online (Sandbox Code Playgroud)

神奇的可重用助手类:

public class PassMissingRoot implements FailureHandler {
    private final FailureHandler defaultHandler
            = new DefaultFailureHandler(InstrumentationRegistry.getTargetContext());
    @Override public void handle(Throwable error, Matcher<View> viewMatcher) {
        if (!(error instanceof NoMatchingRootException)) {
            defaultHandler.handle(error, viewMatcher);
        }
    }
}

public class WindowManagerLayoutParamTypeMatcher extends TypeSafeMatcher<Root> {
    private final String description;
    private final int type;
    private final boolean expectedWindowTokenMatch;
    public WindowManagerLayoutParamTypeMatcher(String description, int type) {
        this(description, type, true);
    }
    public WindowManagerLayoutParamTypeMatcher(String description, int type, boolean expectedWindowTokenMatch) {
        this.description = description;
        this.type = type;
        this.expectedWindowTokenMatch = expectedWindowTokenMatch;
    }
    @Override public void describeTo(Description description) {
        description.appendText(this.description);
    }
    @Override public boolean matchesSafely(Root root) {
        if (type == root.getWindowLayoutParams().get().type) {
            IBinder windowToken = root.getDecorView().getWindowToken();
            IBinder appToken = root.getDecorView().getApplicationWindowToken();
            if (windowToken == appToken == expectedWindowTokenMatch) {
                // 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;
    }
}
Run Code Online (Sandbox Code Playgroud)


anu*_*ain 5

在 espresso 中测试 toast 消息的最佳方法是使用自定义匹配器:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在测试用例中使用它:

  1. 测试是否显示 Toast 消息

    onView(withText(R.string.message)).inRoot(new ToastMatcher())
    .check(matches(isDisplayed()));
    
    Run Code Online (Sandbox Code Playgroud)
  2. 测试是否不显示 Toast 消息

    onView(withText(R.string.message)).inRoot(new ToastMatcher())
    .check(matches(not(isDisplayed())));
    
    Run Code Online (Sandbox Code Playgroud)
  3. Toast 包含特定文本消息的测试 ID

    onView(withText(R.string.message)).inRoot(new ToastMatcher())
    .check(matches(withText("Invalid Name"));
    
    Run Code Online (Sandbox Code Playgroud)

我从我的博客中复制了这个答案 - http://qaautomated.blogspot.in/2016/01/how-to-test-toast-message-using-espresso.html


Cat*_*ina -2

您可以在此处查看源代码并创建您自己的视图匹配器,其功能恰恰相反。