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

如何在Android 11中使用Espresso验证Toast是否显示?

在Android 11中使用Espresso验证Toast显示的解决方案

Android 11及更高版本对Toast的显示机制做了调整——Toast不再由应用进程托管,而是由系统进程负责渲染,这直接导致原本针对Android 10及以下版本的withDecorView匹配方法失效,因为Espresso无法跨进程捕获系统层级的Toast窗口。

下面提供几种可行的解决方案:

方案一:使用UiAutomator跨进程检测Toast

UiAutomator支持跨进程获取系统UI元素,能直接检测到系统托管的Toast,是兼容性最好的方案。

步骤1:添加UiAutomator依赖

在模块的build.gradle中添加依赖:

androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'

步骤2:编写测试代码

import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiSelector;
import androidx.test.uiautomator.Until;
import android.widget.Toast;
import androidx.test.platform.app.InstrumentationRegistry;

// 在测试方法中
UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
// 匹配指定文本的Toast
UiSelector toastSelector = new UiSelector()
        .text("Toast message here")
        .className(Toast.class.getName());

// 等待Toast显示,超时时间5秒
assertTrue("Toast未正常显示", device.wait(Until.hasObject(toastSelector), 5000));

方案二:自定义Toast管理类(需修改应用代码)

如果允许修改应用源码,可以通过单例类统一管理Toast的显示状态,测试时直接读取该状态即可,无需依赖系统窗口检测。

步骤1:实现Toast管理类

public class ToastManager {
    private static String currentToastText;

    public static void showToast(Context context, String text) {
        currentToastText = text;
        Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
    }

    public static String getCurrentToastText() {
        return currentToastText;
    }

    // 测试完成后清理状态,避免影响其他测试用例
    public static void clearToastState() {
        currentToastText = null;
    }
}

步骤2:替换应用中的Toast调用

将原本的Toast.makeText()替换为ToastManager.showToast()。

步骤3:编写测试代码

// 触发显示Toast的操作
onView(withId(R.id.your_button_id)).perform(click());

// 验证Toast内容
assertEquals("Toast message here", ToastManager.getCurrentToastText());

// 测试结束后清理状态
ToastManager.clearToastState();

这种方案的优势是测试速度快,不受系统版本限制;缺点是需要侵入应用代码,适合内部可控的项目。

方案三:自定义RootMatcher(兼容性有限)

部分设备上可以通过扩展Espresso的RootMatcher来匹配系统Toast窗口,但稳定性不如前两种方案,仅作参考:

import android.view.WindowManager;
import android.view.View;
import androidx.test.espresso.Root;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;

public class ToastRootMatcher extends TypeSafeMatcher<Root> {
    @Override
    protected boolean matchesSafely(Root root) {
        int windowType = root.getWindowLayoutParams().get().type;
        // 匹配Toast或应用覆盖层类型的窗口
        if (windowType == WindowManager.LayoutParams.TYPE_TOAST || 
            windowType == WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY) {
            View decorView = root.getDecorView();
            return decorView.getWindowToken() != decorView.getApplicationWindowToken();
        }
        return false;
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("匹配Toast窗口");
    }
}

测试时使用该Matcher:

Espresso.onView(withText("Toast message here"))
        .inRoot(new ToastRootMatcher())
        .check(matches(isDisplayed()));

总结

  • 优先选择方案一(UiAutomator),无需修改应用代码,兼容性覆盖Android 11及以上版本;
  • 若项目允许修改应用代码,方案二是更高效的测试方式;
  • 方案三仅适合部分场景,稳定性不足,谨慎使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 07:40:20