Espresso - 点击对话框的按钮

Posted

技术标签:

【中文标题】Espresso - 点击对话框的按钮【英文标题】:Espresso - click on the button of the dialog 【发布时间】:2016-03-30 02:07:55 【问题描述】:

我想测试 android 6 的权限,但是我没有找到使用 Espresso 点击“允许”按钮的方法。有没有办法做到这一点?

Espresso 的版本是 2.2.1。

测试:

    @Test
    public void acceptFirstPermission() throws Exception 
        onView(withText("ALLOW")).perform(click());
    

行为:

我仍然收到带有对话框的冻结屏幕(如屏幕截图所示)。测试一直执行,直到他完成。

输出:

Running tests
Test running started
android.support.test.espresso.NoActivityResumedException: No activities in stage RESUMED. Did you forget to launch the activity. (test.getActivity() or similar)?
at dalvik.system.VMStack.getThreadStackTrace(Native Method)
at java.lang.Thread.getStackTrace(Thread.java:580)
at android.support.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:82)
at android.support.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:53)
at android.support.test.espresso.ViewInteraction.runSynchronouslyOnUiThread(ViewInteraction.java:184)
at android.support.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:115)
at android.support.test.espresso.ViewInteraction.perform(ViewInteraction.java:87)
at com.walletsaver.app.test.espresso.MarshmallowPermissionsTest.acceptFirstPermission(MarshmallowPermissionsTest.java:31)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at android.support.test.internal.statement.UiThreadStatement.evaluate(UiThreadStatement.java:55)
at android.support.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:257)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:54)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:240)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1879)

Finish

【问题讨论】:

Android Marshmallow: Test permissions with Espresso?的可能重复 【参考方案1】:

我刚刚遇到了同样的问题,需要动态允许或拒绝权限,但需要能够找到按钮以在不使用字符串的情况下单击权限对话框(因为我们将在一系列其他语言中运行以及英语)。

我已经为 Android 使用的字符串 Allow 和 Deny 寻找了一个常量,但找不到,因此选择了浏览布局以查找具有应用程序名称的布局的有点复杂的选项,如权限对话框中所示(例如在本例中为“WalletSaver”),然后转到对话框的父布局,然后深入到我想要的其他 UI 元素。注意:APP_NAME 只是在弹出对话框中为您的应用名称显示的用户可见字符串(因为您可以控制应用的名称以及是否翻译) - 在本例中为“WalletSaver 调试”。

protected fun clickPermissionDeny() 
    var dev = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
    var deny : UiObject2
    if (dev.findObjects(By.textContains(APP_NAME))[0].parent.parent.parent.children[1].childCount == 1)  // If there is no "don't ask again"
        deny = dev.findObjects(By.textContains(APP_NAME))[0].parent.parent.parent.children[1].children[0].children[1].children[0]
     else  // Else move past checkbox
        deny = dev.findObjects(By.textContains(APP_NAME))[0].parent.parent.parent.children[1].children[1].children[0].children[0]
    
    deny.click();


protected fun clickPermissionAllow() 
    var dev = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
    var allow : UiObject2
    while(dev.findObjects(By.textContains(APP_NAME))[0].parent.parent.parent.childCount<2)
        Thread.sleep(100);
    if (dev.findObjects(By.textContains(APP_NAME))[0].parent.parent.parent.children[1].childCount == 1)  // If there is no "don't ask again"
        allow = dev.findObjects(By.textContains(APP_NAME))[0].parent.parent.parent.children[1].children[0].children[1].children[1]
     else  // Else move past checkbox
        allow = dev.findObjects(By.textContains(APP_NAME))[0].parent.parent.parent.children[1].children[1].children[1].children[1]
    
    allow.click()

虽然不是很漂亮,但希望它可以用于跨多种语言的 ui 测试。

已编辑:更新以处理用户第一次拒绝请求(没有复选框)、第二次出现复选框时的情况。

【讨论】:

【参考方案2】:

如果您将 UI-Automator 与 AndroidX 一起使用,您可以找到对话框和按钮。

这是一个gradle依赖代码。

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

您可以使用此代码访问ALLOW 按钮。

这是 Kotlin 代码。

val button = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
                .findObject(
                    UiSelector().text(
                        activityTestRule
                            .activity
                            .getString(R.string.allow_button)
                            .toUpperCase()
                    )
                )

if (button.exists() && button.isEnabled) 
    button.click()

【讨论】:

【参考方案3】:

如果对话框出现,您可以使用动态方式接受权限,如果没有出现,将授予权限,不会抛出任何错误

 private static void allowPermissionsIfNeeded() 
        if (Build.VERSION.SDK_INT >= 23) 
            UiDevice device = UiDevice.getInstance(getInstrumentation());
            UiObject allowPermissions = device.findObject(new UiSelector().text("ALLOW"));
            if (allowPermissions.exists()) 
                try 
                    allowPermissions.click();
                 catch (UiObjectNotFoundException e) 
                    e.printStackTrace();
                
            
        
    

【讨论】:

【参考方案4】:

下面的 sn-p 将在您运行测试之前授予权限。希望它能解决您的问题:)

 @Before
    public void grantPhonePermission() 
        // In M+, trying to call a number will trigger a runtime dialog. Make sure
        // the permission is granted before running this test.
        // goo.gl/C8T4BU
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
            getInstrumentation().getUiAutomation().executeShellCommand(
                    "pm grant " + getTargetContext().getPackageName()
                            + " android.permission.READ_PHONE_STATE"
                            + " android.permission.PHONE");
        
    

【讨论】:

【参考方案5】:

嗯,可以这么简单

onView(withText("Allow")).perform(click());

当然,这不是一个完美的解决方案,因此有两种方法可以使其更加健壮:使用 hierarchyviewer 分析应用程序以找到有关如何识别按钮的提示(例如内容描述),或者深入研究提示的 Android 源代码(例如按钮的资源 ID)。

编辑

嗯,事情没那么简单。我写了an article 关于使用 UiAutomator 来完成这项工作。

【讨论】:

不幸的是,它不起作用。我仍然收到带有对话框的冻结屏幕(就像问题中的屏幕截图一样)。测试一直执行,直到他完成。 你能用你的测试代码更新你的问题吗?通常,如果测试没有通过文本找到按钮,它就会失败。 你真的忘记调用getActivity(),正如测试结果所显示的那样? 其实Activity是可见的,等待action。我不明白你建议如何调用 test.getActivity()。你能用代码示例更新你的答案吗? espresso 不会与警报交互,只有应用程序本身【参考方案6】:

我了解到您正在尝试测试应用权限。我认为用 Espresso 测试它可能是不可能的。您可能需要使用另一个名为 uiatomator 的 UI 测试工具来执行此操作。

uiatomator,谷歌制作的另一个很棒的工具可以让你测试你的Android系统功能,比如通知和屏幕锁定。您可以将它与 Espresso 测试框架一起使用。

如需了解更多信息,请阅读这篇文章:

http://qathread.blogspot.com/2015/05/espresso-uiautomator-perfect-tandem.html

和 uiautomator 文档,您可以找到 here。

【讨论】:

UI Automator 与权限对话框完美配合。谢谢!

以上是关于Espresso - 点击对话框的按钮的主要内容,如果未能解决你的问题,请参考以下文章

Espresso:匹配对话框下的视图

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

使用 espresso 运行的 UIAutomator

C#的文件管理 点击浏览按钮 出现对话框选择文件路径

Android开发,点击按钮弹出对话框的问题

MFC点击按钮打开对话框选择文件夹(不是文件)