检查 Espresso 是不是显示对话框

Posted

技术标签:

【中文标题】检查 Espresso 是不是显示对话框【英文标题】:Check if a dialog is displayed with Espresso检查 Espresso 是否显示对话框 【发布时间】:2014-01-10 13:25:12 【问题描述】:

我正在尝试使用新的android-test-kit (Espresso) 编写一些测试。但我找不到任何关于如何检查是否显示对话框并对其执行一些操作的信息(例如单击正面和负面按钮等)。请注意,WebView 也可能会显示一个对话框,而不是它自己的应用程序。

任何帮助将不胜感激。我只需要一个链接,或者一些基本的示例代码:

    检查是否出现对话框 点击对话框按钮 与对话框的内部视图交互(如果是自定义视图) 在对话框外点击预制件,并检查它是否正在显示(例如,如果在对话框构建器上调用了setCancelable(false),我们想要检查它)

谢谢你的建议!

【问题讨论】:

对我下面的回答有任何反馈吗?? 【参考方案1】:

    要验证是否出现对话框,您只需检查是否显示了带有对话框内文本的视图:

    onView(withText("dialogText")).check(matches(isDisplayed()));
    

    或者,基于带有 id 的文本

    onView(withId(R.id.myDialogTextId)).check(matches(allOf(withText(myDialogText), isDisplayed()));
    

    要单击对话框按钮,请执行以下操作(按钮 1 - 确定,按钮 2 - 取消):

    onView(withId(android.R.id.button1)).perform(click());
    

    更新

    我认为这是可能的,因为 Espresso 有 multi window support。 不确定是否在自定义对话框视图之外单击,但要检查它是否正在显示,您必须创建自定义匹配器并在其中检查。

【讨论】:

第 1 步在 ProgressDialog 上对我不起作用。只是试图验证对话框的标题和消息 espresso 和静态导入是什么?这些方法来自哪些类?为什么要在堆栈溢出答案上使用静态导入? @jvrodrigues 每个 Espresso 教程都使用静态导入。我建议你习惯它(尽管我理解这种挫败感)。这有帮助:google.github.io/android-testing-support-library/docs 对于第 4 步,您可以调用“pressBack();”而不是单击对话框外部这会关闭对话框。这相当于使用硬件后退按钮。 @denys 项目已被移动。链接好像失效了。【参考方案2】:

我目前正在使用它,它似乎工作正常。

onView(withText(R.string.my_title))
    .inRoot(isDialog()) // <---
    .check(matches(isDisplayed()));

【讨论】:

完美。像魅力一样工作! 这对我有用,而接受的答案却没有【参考方案3】:

如果你有这样的 AlertDialog:

您可以检查组件是否显示:

int titleId = mActivityTestRule.getActivity().getResources()
        .getIdentifier( "alertTitle", "id", "android" );

onView(withId(titleId))
        .inRoot(isDialog())
        .check(matches(withText(R.string.my_title)))
        .check(matches(isDisplayed()));

onView(withId(android.R.id.text1))
        .inRoot(isDialog())
        .check(matches(withText(R.string.my_message)))
        .check(matches(isDisplayed()));

onView(withId(android.R.id.button2))
        .inRoot(isDialog())
        .check(matches(withText(android.R.string.no)))
        .check(matches(isDisplayed()));

onView(withId(android.R.id.button3))
        .inRoot(isDialog())
        .check(matches(withText(android.R.string.yes)))
        .check(matches(isDisplayed()));

并执行一个动作:

onView(withId(android.R.id.button3)).perform(click());

【讨论】:

在我的例子中,文本的 ID 为 android.R.id.message,标题的隐藏 ID 为 android.R.id.alertTitle 如果您使用来自 AppCompat 支持库的 AlertDialog(或 DialogFragment),请使用:int alertDialogTitleId = android.support.v7.appcompat.R.id.alertTitle; 如果有人需要知道参数值,***.com/a/15488321/1713366。如果您不知道名称或 def 类型,请尝试 check() 一个不存在的视图并查看 logcat 上的布局层次结构。你会看到一堆这样的defType = name。例如message=hello world,那么你的参数应该看起来像"hello world", "message", "your package name"【参考方案4】:

为了回答已接受的答案没有的问题 4,我修改了以下代码,我在 Stack Overflow (link) 上找到了该代码,用于测试是否显示了 Toast。

@NonNull
public static ViewInteraction getRootView(@NonNull Activity activity, @IdRes int id) 
    return onView(withId(id)).inRoot(withDecorView(not(is(activity.getWindow().getDecorView()))));

传入的id 是当前显示在对话框中的View 的ID。你也可以这样写方法:

@NonNull
public static ViewInteraction getRootView(@NonNull Activity activity, @NonNull String text) 
    return onView(withText(text)).inRoot(withDecorView(not(is(activity.getWindow().getDecorView()))));

现在它正在寻找包含特定文本字符串的View

像这样使用它:

getRootView(getActivity(), R.id.text_id).perform(click());

【讨论】:

【参考方案5】:

按钮 ID R.id.button1 和 R.id.button2 在设备间不会相同。 ID 可能会随操作系统版本而变化。

实现这一点的正确方法是使用 UIAutomator。 在 build.gradle 中包含 UIAutomator 依赖项

// Set this dependency to build and run UI Automator tests
  androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'

并使用

// Initialize UiDevice instance
UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());

// Search for correct button in the dialog.
UiObject button = uiDevice.findObject(new UiSelector().text("ButtonText"));
if (button.exists() && button.isEnabled()) 
    button.click();

【讨论】:

其实android.R.id.button1android.R.id.button2android.R.id.button3代表“正”、“中性”和“负”,是可以使用的全局符号。如果您选择通过文本选择按钮 - 这完全没问题 - 您不需要 UIAutomator,但可以使用 Espresso 的onView(withText("ButtonTest")).perform(click()) 我将此解决方案与 Robotium 测试框架一起使用,并且能够轻松选择 Android OS 对话框按钮。节省了我很多时间。谢谢 jaydeepw! @ThomasKeller 我过去使用过 button1、button2 id,当我在各种设备上运行它们时,我的测试被破坏了。显示的对话框是系统控制。不是您的控件/用户界面。对于 UI 之外的任何内容,建议使用 UIAutomator。 就是这样。非常感谢。【参考方案6】:

以防万一有人像我一样偶然发现这个问题。所有答案仅适用于带有对话框按钮的对话框。不要尝试在没有用户交互的情况下将其用于进度对话框。 Espresso 一直在等待应用程序进入空闲状态。只要进度对话框可见,应用就不会处于空闲状态。

【讨论】:

【参考方案7】:

如果您不想在对话框中检查特定字符串,可以使用hasWindowFocus(),如下所示:

// Kotlin, with ActivityScenarioRule
activityScenarioRule.scenario.onActivity  activity ->
   val dialogIsDisplayed = !activity.hasWindowFocus()


// Kotlin, with ActivityTestRule
val dialogIsDisplayed = !activityTestRule.activity.hasWindowFocus()


// Java 7, with ActivityScenarioRule
activityScenarioRule.getScenario().onActivity(new ActivityScenario.ActivityAction<MyActivity>() 
    @Override
    public void perform(MyActivity activity) 
        boolean dialogIsDisplayed = !activity.hasWindowFocus();
    
);

// Java, with ActivityTestRule
boolean dialogIsDisplayed = !activityTestRule.getActivity().hasWindowFocus();

来源:

How to check if the current activity has a dialog in front? How to Access Activity from ActivityScenarioRule

【讨论】:

以上是关于检查 Espresso 是不是显示对话框的主要内容,如果未能解决你的问题,请参考以下文章

Espresso:匹配对话框下的视图

使用 espresso 运行的 UIAutomator

如何使用 Espresso 将时间设置为 MaterialDateTimePicker

我们可以在 aws 设备场中为 Android espresso 测试禁用一个对话框吗

如何使用PHP检查是不是在下载对话框上单击了保存按钮?

浓缩咖啡测试失败,进度对话框未从顶部删除