Android Marshmallow:使用Espresso测试权限?

问题描述 投票:57回答:11

Android Marshmallow引入的新权限方案要求在运行时检查特定权限,这意味着需要根据用户是否拒绝或允许访问来提供不同的流。

当我们使用Espresso在我们的应用程序上运行自动UI测试时,我们如何模拟或更新权限状态以测试不同的场景?

android permissions android-espresso android-6.0-marshmallow
11个回答
72
投票

随着Android Testing Support Library 1.0的新版本,你可以在测试中使用GrantPermissionRule在开始任何测试之前授予许可。

@Rule public GrantPermissionRule permissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);

Kotlin解决方案

@get:Rule var permissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION)

必须使用@get:Rule以避免java.lang.Exception: The @Rule 'permissionRule' must be public.更多信息here


0
投票

Android测试支持库中有GrantPermissionRule,您可以在测试中使用它来在开始任何测试之前授予权限。

requestPermissions()

0
投票

谢谢@niklas的解决方案。如果有人想在Java中授予多个权限:

@Rule public GrantPermissionRule permissionRule = GrantPermissionRule.grant(android.Manifest.permission.CAMERA, android.Manifest.permission.ACCESS_FINE_LOCATION);

35
投票

接受的答案实际上并未测试权限对话框;它只是绕过它。因此,如果权限对话框由于某种原因失败,则您的测试将给出错误的绿色。我鼓励实际点击“授予权限”按钮来测试整个应用行为。

看看这个解决方案:

public static void allowPermissionsIfNeeded(String permissionNeeded) {
    try { 
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !hasNeededPermission(permissionNeeded)) {
        sleep(PERMISSIONS_DIALOG_DELAY);
        UiDevice device = UiDevice.getInstance(getInstrumentation());
        UiObject allowPermissions = device.findObject(new UiSelector()
          .clickable(true) 
          .checkable(false) 
          .index(GRANT_BUTTON_INDEX));
        if (allowPermissions.exists()) {
          allowPermissions.click();
        } 
      } 
    } catch (UiObjectNotFoundException e) {
      System.out.println("There is no permissions dialog to interact with");
    } 
  } 

在这里找到全班:https://gist.github.com/rocboronat/65b1187a9fca9eabfebb5121d818a3c4

顺便说一下,由于这个答案一直很流行,我们将Qazxswpoi添加到Barista,我们的Espresso和UiAutomator之上的工具将绿色仪器测试:PermissionGranter检查出来,因为我们将通过发布来维护它。


29
投票

当您的手机使用英语语言环境时,请尝试使用此类静态方法:

https://github.com/SchibstedSpain/Barista

我发现它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) { Timber.e(e, "There is no permissions dialog to interact with "); } } } }


20
投票

您可以在运行测试之前授予权限,例如:

here

但是你无法撤销。如果你尝试@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. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { getInstrumentation().getUiAutomation().executeShellCommand( "pm grant " + getTargetContext().getPackageName() + " android.permission.CALL_PHONE"); } } pm reset-permissions,这个过程就会被杀死。


11
投票

实际上到目前为止,有两种方法可以做到这一点:

  1. 在测试开始之前使用adb命令授予权限(pm revoke...):

documentation

  1. 您可以单击权限对话框并使用UIAutomator(adb shell pm grant "com.your.package" android.permission.your_permission)设置权限。如果您的测试是使用Espresso for Android编写的,您可以轻松地将Espresso和UIAutomator步骤结合在一起。

7
投票

您可以在开始测试之前通过授予权限轻松实现此目的。例如,如果您在测试运行期间应该使用相机,则可以按如下方式授予权限

documentation

3
投票

ESPRESSO UPDATE

这一行代码授予grant方法中作为参数列出的每个权限,并立即生效。换句话说,应用程序将被视为已经授予权限 - 不再有对话框

@Before
public void grantPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        getInstrumentation().getUiAutomation().executeShellCommand(
                "pm grant " + getTargetContext().getPackageName()
                        + " android.permission.CAMERA");
    }
}

和gradle

@Rule @JvmField
val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION)

参考:dependencies { ... testImplementation "junit:junit:4.12" androidTestImplementation "com.android.support.test:runner:1.0.0" androidTestImplementation "com.android.support.test.espresso:espresso-core:3.0.0" ... }


0
投票

我知道答案已被接受,但是,不是一遍又一遍地建议的https://www.kotlindevelopment.com/runtime-permissions-espresso-done-right/语句,另一种更优雅的方法是在特定版本的操作系统的实际测试中执行以下操作:

if

如果使用表达式求值为false调用@Test fun yourTestFunction() { Assume.assumeTrue(Build.VERSION.SDK_INT >= 23) // the remaining assertions... } 函数,则测试将暂停并被忽略,我假设这是您在SDK 2之前的设备上执行测试时所需的。


0
投票

我已经实现了一个利用包装类,覆盖和构建变体配置的解决方案。解决方案很长,需要解释并在此处找到:assumeTrue

它还没有包装在一个sdk中,但主要的想法是覆盖https://github.com/ahasbini/AndroidTestMockPermissionUtilsContextWrapper.checkSelfPermission的功能被操纵并返回模拟结果欺骗应用程序进入不同的场景进行测试如下:权限被拒绝因此应用程序请求它并结束获得许可。即使应用程序一直拥有该权限,也会发生这种情况,但这个想法是它被来自重写实现的模拟结果所欺骗。

此外,该实现有一个名为ActivityCompat.requestPermissionsTestRule类,可以在测试类中使用它来轻松模拟所有条件以无缝地测试权限。此外,断言可以像确保应用程序调用PermissionRule一样。

© www.soinside.com 2019 - 2024. All rights reserved.