检测棉花糖中的吐司

Posted

技术标签:

【中文标题】检测棉花糖中的吐司【英文标题】:Detecting toasts in Marshmallow 【发布时间】:2016-01-28 10:31:17 【问题描述】:

我正在用 espresso 编写一些 ui 测试,并且正在尝试断言 toast 消息。我遇到的问题是我的代码在 Lollipop 上工作,但在棉花糖上失败,我不明白为什么。

我的代码基本上是打开一个对话框、填写一封电子邮件并单击一个按钮。这应该会带来一个 toast 并且确实如此(我通过设备上的目视检查确认)但我的测试未能检测到 toast。

为此,我为 toast 创建了一个自定义匹配器类:

import android.os.IBinder;
import android.support.test.espresso.Root;
import android.view.WindowManager;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;

import static com.google.android.exoplayer.util.Assertions.checkArgument;
import static com.google.android.exoplayer.util.Assertions.checkNotNull;
import static org.hamcrest.CoreMatchers.equalTo;

public class ToastMatcher

    public static Matcher<Root> withToastText(String toastText) 
        // use preconditions to fail fast when a test is creating an invalid matcher.
        checkArgument(!(toastText.equals(null)));
        return withToastText(equalTo(toastText));
    

    public static Matcher<Root> withToastText(final Matcher<String> matcherText) 

        // use preconditions to fail fast when a test is creating an invalid matcher.
        checkNotNull(matcherText);
        return new TypeSafeMatcher<Root>() 

            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;
            

        ;
    

至于我的测试用例

@Test
public void success() 
    String successMessage = mActivityRule.getActivity().getResources().getString(R.string.info_recover_instructions);
    String ok = mActivityRule.getActivity().getResources().getString(android.R.string.ok);
    // Click forgot button
    onView(withId(R.id.lg_forgot)).perform(click());
    // Fill email
    onView(withClassName(endsWith("EditText"))).perform(typeText(USERNAME));
    // Click OK button
    onView(withText(ok))
            .check(matches(isEnabled()))
            .perform(click());
    // Assert Toast
    onView(withText(successMessage)).inRoot(ToastMatcher.withToastText(successMessage)).check(matches(isDisplayed()));

正如我之前所说,这在 Lollipop 上运行得很好,但在 Marshmallow 上它给了我以下错误:

android.support.test.espresso.NoMatchingRootException: Matcher 'is toast' did not match any of the following roots: [Rootapplication-window-token=android.view.ViewRootImpl$W@a66b932, window-token=android.view.ViewRootImpl$W@a66b932, has-window-focus=true, layout-params-type=2, layout-params-string=WM.LayoutParams(0,0)(wrapxwrap) gr=#11 sim=#20 ty=2 fl=#1820002 fmt=-3 wanim=0x103045c needsMenuKey=2, decor-view-string=DecorViewid=-1, visibility=VISIBLE, width=1026, height=483, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1, Rootapplication-window-token=android.view.ViewRootImpl$W@8d64683, window-token=android.view.ViewRootImpl$W@8d64683, has-window-focus=false, layout-params-type=2, layout-params-string=WM.LayoutParams(0,0)(wrapxwrap) gr=#11 sim=#20 ty=2 fl=#1800002 fmt=-3 wanim=0x103045c needsMenuKey=2, decor-view-string=DecorViewid=-1, visibility=VISIBLE, width=1026, height=598, has-focus=true, has-focusable=true, has-window-focus=false, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1, Rootapplication-window-token=android.view.ViewRootImpl$W@90a2000, window-token=android.view.ViewRootImpl$W@90a2000, has-window-focus=false, layout-params-type=1, layout-params-string=WM.LayoutParams(0,0)(fillxfill) ty=1 fl=#81810100 wanim=0x103045b needsMenuKey=2, decor-view-string=DecorViewid=-1, visibility=VISIBLE, width=1080, height=1920, has-focus=true, has-focusable=true, has-window-focus=false, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=3]

我做错了什么还是应该在 android Marshmallow 上做不同的事情?

【问题讨论】:

您是否尝试通过文字来敬酒? 是的。我尝试简单地做 onView(withText(successMessage)).check(matches(isDisplayed())) 但这也不起作用,所以我创建了自定义匹配器,它在除 MM 之外的其他 android 版本上工作得很好 【参考方案1】:

试试这个。不确定它是否适用于棉花糖:

onView(withText(R.string.toastText))    
    .inRoot(withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView()))))
        .check(matches(isDisplayed()));

【讨论】:

嗨。我试过了,但它也没有检测到棉花糖上的吐司

以上是关于检测棉花糖中的吐司的主要内容,如果未能解决你的问题,请参考以下文章

Android Studio getSlotFromBufferLocked:棉花糖中的未知缓冲区错误

获取棉花糖中的当前位置 0,其中 23 API 以下使用融合位置给出准确的当前位置

清除棉花糖中所有应用程序的缓存?

在棉花糖中获取蓝牙本地mac地址

带有比例标签的动画列表在棉花糖中不起作用

如何在棉花糖中首次启动应用程序时获取位置访问权限