Android在每次测试开始时撤消权限

Cha*_* Li 13 android android-testing android-permissions android-espresso android-uiautomator

我正在使用Espresso和UIAutomator来编写我的测试用例.我正在测试外部存储权限,当它被拒绝时以及何时被允许.我有不同的测试用例,都需要在测试用例开始时撤销权限.但是,某些测试用例应该并且确实会导致授予权限,因此我需要在执行下一个测试时撤消权限.我一直在搜索,我遇到的最接近的事情是使用pm管理器执行adb shell命令来撤销权限.但是,通过这样做,我将收到以下错误,由于"进程崩溃",Instrumentation运行失败.有没有什么办法可以确保在每个测试用例开始时撤销权限?如果没有,如何解决有关测试权限的问题?提前谢谢你的帮助!

这是我目前在每个测试用例之前撤消权限的代码片段(不起作用):

@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");
    }
}
Run Code Online (Sandbox Code Playgroud)

尝试使用上面的代码段撤消权限时出现相应的错误消息:

Test failed to run to completion. Reason: 'Instrumentation run failed due to 'Process crashed.''.
Run Code Online (Sandbox Code Playgroud)

我也遇到过这两个帖子:这个这个.

col*_*ots 8

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")
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您从 shell 脚本运行测试,则只需在开始每个测试之前使用以下 shell 命令之一即可。

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
Run Code Online (Sandbox Code Playgroud)

无论您是从自定义 AndroidJUnitRunner 的 onCreate() 或 onStart() 撤销权限,还是从测试中间撤销权限,都会发生相同的崩溃。即使活动尚未打开,您也无法在仪器测试期间撤销权限而不崩溃。

似乎最好的选择是在运行任何仪器测试之前撤销 Gradle 的所有权限,然后您可以在测试开始之前使用 GrantPermissionRule 重新启用您想要设置的任何权限

Android Test Orchestrator计划在每次测试之间自动清除所有数据,但目前该功能仍然不存在。我提交了一个错误,您可以投票以在测试之间进行自动清理。


Sag*_*gar 7

在测试开始之前,您不应撤消任何许可。这将重新启动整个测试应用程序过程,并且该测试将标记为失败。

相反,您可以在测试执行完成后即@After通过如下方法撤消许可:

@After
fun tearDown(){
    InstrumentationRegistry.getInstrumentation().uiAutomation.
            executeShellCommand("pm revoke ${getTargetContext().packageName} android.permission.WRITE_EXTERNAL_STORAGE")
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用Android Test Orchestrator 1.0.2版并进行设置

 testInstrumentationRunnerArguments clearPackageData: 'true'
Run Code Online (Sandbox Code Playgroud)

这将在每次测试后清除包装数据。

注意:v1.0.2在通过Jacoco管理代码覆盖率报告时,Android Test Orchestrator 出现问题。

  • Android Test Orchestrator 看起来是不错的选择。通过配置clearPackageData,每次执行时默认都会撤销所有权限,因此您只需启用正确的权限即可。 (2认同)

小智 2

我不确定如何在运行时执行此操作而不提示用户。但是,您在标题中指出这是为了测试目的。因此我有一些选择可以建议你

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您需要的话,我可以给您更多关于 b)(如何请求权限)的链接(只需评论即可)。但是,由于我不确定您是否会对这个答案感兴趣,因此我不会花时间来记录此选项。

但是,也许有人能够向您解释如何在运行时直接执行此操作而无需提示,但我认为至少向您提供这些信息可能会很有趣。