web-dev-qa-db-ja.com

Android各テストの開始時に権限を取り消す

EspressoとUIAutomatorを使用してテストケースを作成しています。拒否されたときと許可されたときの外部ストレージのアクセス許可をテストしています。さまざまなテストケースがありますが、すべてテストケースの開始時に取り消す許可が必要です。ただし、一部のテストケースでは、アクセス許可が付与される必要があります。そのため、次のテストの実行時にアクセス許可を取り消す必要があります。私は周りを検索しましたが、最も近いのは、pmマネージャーを使用してadb Shellコマンドを実行し、アクセス許可を取り消すことです。ただし、そうすることで、次のエラーが発生します。「プロセスのクラッシュ」が原因でインストルメンテーションの実行に失敗しました。すべてのテストケースの開始時にアクセス許可が取り消されていることを確認する方法はありますか?そうでない場合、アクセス許可のテストに関してこの問題をどのように解決できますか?よろしくお願いします!

これは、現在、各テストケースの前にアクセス許可を取り消す必要があるコードスニペットです(これは機能しません)。

@Before
public void setUp() {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop) {
        getInstrumentation().getUiAutomation().executeShellCommand(
                "pm revoke " + getTargetContext().getPackageName()
                        + " Android.permission.WRITE_EXTERNAL_STORAGE");
    }
}

上記のコードスニペットで権限を取り消そうとすると、対応するエラーメッセージが表示されます。

Test failed to run to completion. Reason: 'Instrumentation run failed due to 'Process crashed.''.

thisthis の2つの投稿にも出くわしました。

13
Charles Li

テストを開始する前に、権限を取り消さないでください。これにより、テストアプリプロセス全体が再起動し、テストは失敗としてマークされます。

代わりに、テストの実行が完了した後、つまり@Afterメソッドで次のように権限を取り消すことができます。

@After
fun tearDown(){
    InstrumentationRegistry.getInstrumentation().uiAutomation.
            executeShellCommand("pm revoke ${getTargetContext().packageName} Android.permission.WRITE_EXTERNAL_STORAGE")
}

または、 Android Test Orchestrator バージョン1.0.2を使用して設定することもできます

 testInstrumentationRunnerArguments clearPackageData: 'true'

これにより、各テスト後にパッケージデータがクリアされます。

注:Android Test Orchestrator v1.0.2には、Jacocoを介したコードカバレッジレポートの管理に関して問題があります。

7
Sagar

ADBには権限を取り消す機能がありますが、権限を取り消すとアプリプロセス全体が再起動し、テストが失敗して終了するため、インストルメンテーションテストから呼び出すことはできません。次のKotlinコードは失効を実行しますが、権限が取り消されるとテストがクラッシュします。

/**
 *  Will revoke, but also CRASH if called by a test
 *  Revocation requires a full process restart, which crashes your test process.
 */
fun revokePermissions(vararg permissions: String) {
    permissions.forEach {
        InstrumentationRegistry.getInstrumentation().uiAutomation.
                executeShellCommand("pm revoke ${getTargetContext().packageName} $it")
    }
}

シェルスクリプトからテストを実行する場合は、各テストを開始する前に、次のシェルコマンドのいずれかを使用するだけです。

adb Shell pm revoke com.package.appname Android.permission.CAMERA
adb Shell pm reset-permissions com.package.appname
adb Shell pm clear com.package.appname

カスタムAndroidJUnitRunnerのonCreate()またはonStart()から、またはテストの途中からアクセス許可を取り消しても、同じクラッシュが発生します。アクティビティがまだ開かれていない場合でも、インストルメンテーションテスト中にクラッシュせずに権限を取り消すことはできません。

インストルメンテーションテストを実行する前にGradleからすべての権限を取り消すのが最善のオプションのようです。その後、 GrantPermissionRule を使用して、テストを開始する前に設定する権限を再度有効にすることができます。

Android Test Orchestrator は、各テスト間ですべてのデータを自動的にクリアするように計画されていましたが、その機能は現在も存在しません。 投票できるバグを提出しました テスト間で自動クリーンアップを行います。

3
colintheshots

ユーザーにプロンプ​​トを表示せずに実行時にこれを行う方法がわかりません。しかし、あなたはそれがテスト目的であるとタイトルで述べました。したがって、私はあなたに提案できるいくつかのオプションがあります

a)許可なしにテストを行う必要がある場合は、デバイスの設定を使用して手動でテストを取り消すだけです。

b)確認して許可を求めた後、許可を拒否することができます。カメラの許可を確認して要求するために使用するコードをいくつか紹介します。権限名と、チェックする条件を変更する必要があります。

public static boolean checkCameraPermission(MainActivity thisActivity) {
    return ContextCompat.checkSelfPermission(thisActivity,
            Manifest.permission.CAMERA)
            == PackageManager.PERMISSION_GRANTED;
}

public static void checkAndAskCameraPermission(final MainActivity thisActivity) {

    if (!checkCameraPermission(thisActivity)) {
        //No right is granted
        // Should we show an explanation?
        if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
                Manifest.permission.CAMERA)) {

            //Open a dialog explaining why you are asking permission then when when positive button is triggered, call this line
            ActivityCompat.requestPermissions(thisActivity,
                            new String[]{Manifest.permission.CAMERA},
                            CHECK_FOR_CAMERA_PERMISSION);

        } else {
            // No explanation needed, we can request the permission.
            ActivityCompat.requestPermissions(thisActivity,
                    new String[]{Manifest.permission.CAMERA},
                    CHECK_FOR_CAMERA_PERMISSION);
        }
    }
}

必要に応じて、b)(許可を求める方法)に関するリンクをもう少し提供できます(コメントするだけです)。ただし、この回答に興味があるかどうかわからないため、このオプションを文書化するために時間を費やすことはありません。

しかし、その後、誰かがプロンプトを表示せずに実行時に直接それを行う方法を説明できるかもしれませんが、少なくともこの情報を提供することは興味深いかもしれません。

2
Feuby

できません。権限の付与/取り消しはユーザーの管理下にあります。

ただし、adbを介してアクセス許可を付与/取り消すことができ、プログラムでadbコマンドをトリガーすることもできますが、これが組み合わせて機能するかどうかはわかりません。

adb Shell pm grant [app.package] [permission]
adb Shell pm grant com.app.package.path Android.permission.READ_CONTACTS

ここを見てください

テスト目的で、アクセス許可をブール値にマップする場合がありますか?

2
longilong

私は同じ問題に遭遇し、次の解決策を適用しました(今のところ毎回うまく機能しています)

Gradleタスクを作成します。

task revokeLocationPermissions(type: Exec) {
    def revokeLocationPermission = ['adb', 'Shell', 'pm', 'revoke', 'yourPackageNameHere' , 'Android.permission.ACCESS_FINE_LOCATION']
    commandLine revokeLocationPermission
    outputs.upToDateWhen { false }
}

Run/Debug Configurationsに移動し、Android Instrumented Testを選択します。以下に「起動前:」オプションがあります。プラス記号をクリックして、カスタムgradleタスクを追加します。

Image

それが役に立てば幸い!私は、複数のフレーバー、つまり複数のパッケージ名を持つプロジェクトのスケーラブルなソリューションを見つけようとしていますが、これまでのところ、実際に機能するものはありません。

1
Petermonteer

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

まだSDKにパックされていませんが、主なアイデアは、ContextWrapper.checkSelfPermissionとActivityCompat.requestPermissionsの機能をオーバーライドして、アプリを次のようにテストするさまざまなシナリオに騙して、モックの結果を返すことです。それを要求し、許可を得て終了しました。このシナリオは、アプリがずっと許可を持っていたとしても発生しますが、その考えは、オーバーライドする実装からのモックされた結果によってだまされたということです。

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

1
ahasbini