web-dev-qa-db-ja.com

Android Marshmallow:Espressoで権限をテストしますか?

Android Marshmallowによって導入された新しい許可スキームでは、実行時に特定の許可を確認する必要があります。これは、ユーザーがアクセスを拒否するか許可するかによって異なるフローを提供する必要があることを意味します。

Espressoを使用してアプリで自動UIテストを実行しているときに、さまざまなシナリオをテストするためにアクセス許可の状態をモックまたは更新するにはどうすればよいですか?

58
argenkiwi

Android Testing Support Library 1. の新しいリリースでは、 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.を使用する必要があります。詳細情報 こちら

75
Niklas

受け入れられた答えは、実際に許可ダイアログをテストしません。単にバイパスします。そのため、何らかの理由でアクセス許可ダイアログが失敗した場合、テストは偽の緑色になります。実際に「許可を与える」ボタンをクリックして、アプリの動作全体をテストすることをお勧めします。

このソリューションをご覧ください:

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

ちなみに、この回答は人気のあるものなので、PermissionGranterBaristaに追加しました。インストゥルメンタルテストは緑です。 https://github.com/SchibstedSpain/Barista リリースごとにメンテナンスするため、チェックしてください。

35
Roc Boronat

お使いの携帯電話が英語ロケールにある場合、そのような静的な方法で試してみてください:

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 ");
            }
        }
    }
}

見つけました こちら

29
riwnodennyk

次のような方法で、テストを実行する前にアクセス許可を付与できます。

@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...プロセスは強制終了されます。

20
Jose Alcérreca

実際、これを行うには2つの方法があります。

  1. テストを開始する前にadbコマンドを使用して権限を付与します( documentation ):

adb Shell pm grant "com.your.package" Android.permission.your_permission

  1. 許可ダイアログをクリックして、UIAutomatorを使用して許可を設定できます( documentation )。 AndroidのEspressoを使用してテストが記述されている場合、EspressoとUIAutomatorのステップを1つのテストで簡単に組み合わせることができます。
11
denys

テストを開始する前に許可を与えることで、これを簡単に達成できます。たとえば、テスト実行中にカメラを使用することになっている場合、次のように許可を与えることができます

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

ESPRESSO UPDATE

この1行のコードは、grantメソッドのパラメーターとしてリストされているすべての許可を即時に許可します。つまり、アクセス許可が既に付与されているかのようにアプリが処理されます-これ以上のダイアログはありません

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

参照: https://www.kotlindevelopment.com/runtime-permissions-espresso-done-right/

3
murt

@niklasのソリューションに感謝します。 Javaで複数のアクセス許可を付与しようとしている場合:

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

私は答えが受け入れられたことを知っていますが、何度も繰り返し提案されているifステートメントの代わりに、別のよりエレガントなアプローチは、特定のバージョンの実際のテストで以下を実行することですOS:

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

assumeTrue関数がfalseと評価される式で呼び出された場合、テストは停止して無視されます。これは、SDK 23より前のデバイスでテストが実行されている場合に必要なものであると思われます。

0
Edison Spencer

Android Testing Support LibraryにGrantPermissionRuleがあります。これをテストで使用して、テストを開始する前に許可を与えることができます。

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

ラッパークラスを活用し、バリアント構成をオーバーライドおよびビルドするソリューションを実装しました。ソリューションは説明するのに非常に長く、ここにあります: https://github.com/ahasbini/AndroidTestMockPermissionUtils

SDKにはまだパックされていませんが、主なアイデアは、操作される_ContextWrapper.checkSelfPermission_および_ActivityCompat.requestPermissions_の機能をオーバーライドして、テストされるさまざまなシナリオにアプリをだまして模擬的な結果を返すことです。拒否されたため、アプリはそれを要求し、許可を得て終了しました。このシナリオは、アプリにずっと許可があったとしても発生しますが、アイデアは、オーバーライドする実装からの模擬結果によってtrickされたということです。

さらに、実装にはTestRuleクラスと呼ばれるPermissionRuleクラスがあり、これをテストクラスで使用して、すべての条件を簡単にシミュレートして、アクセス許可をシームレスにテストできます。また、たとえばアプリがrequestPermissions()を呼び出したことを確認するようにアサーションを作成することもできます。

0
ahasbini