Подтвердить что ты не робот

Android Marshmallow: проверить разрешения с помощью Espresso?

Новая схема разрешений, введенная Android Marshmallow, требует проверки определенных разрешений во время выполнения, что подразумевает необходимость предоставления разных потоков в зависимости от того, отрицает ли пользователь или разрешает доступ.

Как мы используем Espresso для запуска автоматических тестов пользовательского интерфейса в нашем приложении, как мы можем макетировать или обновлять состояние разрешений для тестирования разных сценариев?

4b9b3361

Ответ 1

В новом выпуске библиотеки поддержки тестирования Android 1.0 появилась GrantPermissionRule, которую вы можете использовать в своих тестах для предоставления разрешения перед началом любых тестов.

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

Котлин раствор

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

@get:Rule должно использоваться для того, чтобы избежать java.lang.Exception: The @Rule 'permissionRule' must be public. Больше информации здесь.

Ответ 2

Принятый ответ на самом деле не проверяет диалог разрешений; это просто обходит это. Таким образом, если по какой-либо причине диалоговое окно разрешений завершится неудачно, ваш тест даст ложный зеленый цвет. Я рекомендую нажать кнопку "дать разрешения", чтобы проверить поведение всего приложения.

Посмотрите на это решение:

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

Кстати, поскольку этот ответ был популярным, мы добавили PermissionGranter к Barista, нашему инструменту над Espresso и UiAutomator, чтобы сделать инструментальные тесты зелеными: https://github.com/SchibstedSpain/Barista проверить его, потому что мы будем поддерживать это релиз за выпуском.

Ответ 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) {
                Timber.e(e, "There is no permissions dialog to interact with ");
            }
        }
    }
}

Я нашел его here

Ответ 4

Вы можете предоставить разрешения перед запуском теста с чем-то вроде:

@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 или pm revoke..., процесс будет убит.

Ответ 5

На самом деле есть два способа сделать это, я знаю до сих пор:

  • Предоставьте разрешение с помощью команды adb перед началом тестирования (документация):

adb shell pm grant "com.your.package" android.permission.your_permission

  1. Вы можете щелкнуть по диалоговому окну разрешения и установить разрешение с помощью UIAutomator (документация). Если ваши тесты написаны с помощью Espresso для Android, вы можете легко скомбинировать шаги Espresso и UIAutomator в одном тесте.

Ответ 6

Вы можете легко достичь этого, предоставив разрешение перед началом теста. Например, если вы должны использовать камеру во время тестового прогона, вы можете предоставить разрешение следующим образом

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

Ответ 7

ЭСПРЕССО ОБНОВЛЕНИЕ

Эта единственная строка кода дает немедленное действие каждому разрешению, указанному в качестве параметра в методе предоставления. Другими словами, приложение будет обрабатываться так, как если бы разрешения уже были предоставлены - больше никаких диалогов

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

и Gradle

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"
  ...
}

ссылка: https://www.kotlindevelopment.com/runtime-permissions-espresso-done-right/

Ответ 8

Я отключил и восстановил масштаб анимации до и после тестов с использованием эспрессо и adb, например здесь,

и кажется, что он действителен для M-разрешений, так как Stony Wang делает здесь и Denys ответил.

Ответ 9

Я знаю, что ответ был принят, однако, вместо предложения if, которое было предложено снова и снова, еще одним более элегантным подходом было бы сделать следующее в фактическом тесте, который вы хотите использовать для конкретной версии OS:

@Test
fun yourTestFunction() {
    Assume.assumeTrue(Build.VERSION.SDK_INT >= 23)
    // the remaining assertions...
}

Если функция assumeTrue вызывается с выражением, вычисляющим значение false, тест останавливается и игнорируется, и я предполагаю, что вы хотите, если тест выполняется на устройстве pre SDK 23.

Ответ 10

Я реализовал решение, которое использует классы-обертки, переопределяя и конфигурируя варианты сборки. Решение довольно длинное для объяснения и находится здесь: https://github.com/ahasbini/AndroidTestMockPermissionUtils.

Он еще не упакован в SDK, но основная идея состоит в том, чтобы переопределить функциональные возможности ContextWrapper.checkSelfPermission и ActivityCompat.requestPermissions для манипулирования и вернуть имитированные результаты, обманывая приложение в различных сценариях, которые должны быть протестированы, как: разрешение было отклонено, следовательно, приложение отказано просил об этом и закончил с предоставленным разрешением. Этот сценарий будет происходить, даже если приложение все время имело разрешение, но идея заключается в том, что его обманули поддельные результаты переопределяющей реализации.

Кроме того, реализация имеет TestRule называемый классом PermissionRule который можно использовать в тестовых классах, чтобы легко имитировать все условия для TestRule тестирования разрешений. Также можно сделать утверждения, например, убедившись, что приложение requestPermissions().

Ответ 11

В библиотеке поддержки тестирования Android есть GrantPermissionRule, который вы можете использовать в своих тестах для предоставления разрешения перед началом любых тестов.

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

Ответ 12

Спасибо @niklas за решение. В случае, если кто-то хочет предоставить несколько разрешений в Java:

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