You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Espresso测试Toast报NoMatchingRootException异常求解

问题根因

  • 你使用的旧版ToastMatcher仅适配API 30以下系统,Android 11(API 30)后系统Toast的窗口类型不再是TYPE_TOAST,导致匹配逻辑完全失效
  • 测试执行速度快于Toast弹出速度,校验逻辑执行时Toast还未完成渲染,或已经消失

可行解决方案

方案1:使用兼容高版本系统的ToastMatcher+加等待逻辑

  1. 替换原有ToastMatcher为兼容版:
import android.os.Build;
import android.os.IBinder;
import android.view.WindowManager;
import androidx.test.espresso.Root;
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;
        boolean isToastWindowType = false;
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            isToastWindowType = type == WindowManager.LayoutParams.TYPE_TOAST;
        } else {
            isToastWindowType = type == WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        }
        if (isToastWindowType) {
            IBinder windowToken = root.getDecorView().getWindowToken();
            IBinder appToken = root.getDecorView().getApplicationWindowToken();
            return windowToken == appToken;
        }
        return false;
    }
}
  1. 修改测试用例,点击触发Toast的按钮后加等待逻辑,你已实现的waitFor方法可以直接用:
@Test
public void testDialogButtonClick() throws Throwable {
    onView(withId(R.id.activityLoginButtonEnter)).perform(click());
    onView(withId(R.id.activityLoginDialogButton)).perform(click());
    // 等待1秒,保证Toast已弹出且未消失
    onView(isRoot()).perform(waitFor(1000));
    onView(withText("toast text")).inRoot(new ToastMatcher())
            .check(matches(isDisplayed()));
}

方案2:使用Espresso自带匹配器(无需自定义ToastMatcher,更省心)

不用自己维护ToastMatcher的版本兼容逻辑,直接通过匹配非Activity窗口的方式识别Toast:

@Test
public void testDialogButtonClick() throws Throwable {
    onView(withId(R.id.activityLoginButtonEnter)).perform(click());
    onView(withId(R.id.activityLoginDialogButton)).perform(click());
    onView(isRoot()).perform(waitFor(1000));
    // 直接匹配不属于当前Activity的窗口
    onView(withText("toast text"))
            .inRoot(withDecorView(not(is(activityTestRule.getActivity().getWindow().getDecorView()))))
            .check(matches(isDisplayed()));
}

注意事项

  • 测试过程中保持应用在前台、屏幕亮屏,后台状态下系统不会弹出Toast
  • 模拟器/测试机关闭应用的通知拦截权限,部分定制ROM会默认禁止第三方应用弹出Toast

内容的提问来源于stack exchange,提问作者Forged

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 10:06:06