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

时间:2017-04-18 01:37:21

标签: android android-permissions android-espresso android-testing 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");
    }
}

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

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

我还遇到了这两个帖子:thisthis

6 个答案:

答案 0 :(得分:5)

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

相反,您可以在测试执行完成后撤消该权限,即使用@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'

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

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

答案 1 :(得分: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);
        }
    }
}

如果你需要,我可以给你一些关于b)(如何询问权限)的更多链接(只需评论它)。但是,由于我不确定这个答案会让您感兴趣,我不会花时间记录这个选项。

但是,也许有人能够在没有提示的情况下直接在运行时解释你如何做到这一点,但我可能会为你提供至少这些信息。

答案 2 :(得分:2)

你不能。授予/撤销权限由用户控制。

但是,您可以通过adb授予/撤消权限,并且可以通过编程方式触发adb命令,但我不知道这是否可以组合使用?...

adb shell pm grant [app.package] [permission]
adb shell pm grant com.app.package.path android.permission.READ_CONTACTS

look here

您可以将权限映射到布尔值以进行测试吗?

答案 3 :(得分:1)

我已经实现了一个利用包装器类,覆盖和构建变体配置的解决方案。解决方案的解释时间很长,可在此处找到:https://github.com/ahasbini/AndroidTestMockPermissionUtils

它尚未打包在sdk中,但主要思想是覆盖ContextWrapper.checkSelfPermission和ActivityCompat.requestPermissions的功能以进行操作,并返回模拟结果,诱使应用程序进入要测试的不同场景,如:权限被拒绝因此应用程序请求它并以授予的权限结束。即使应用程序一直拥有该权限,也会发生这种情况,但这个想法是它被来自覆盖实现的模拟结果所欺骗。

此外,该实现还有一个名为PermissionRule的TestRule类,可以在测试类中使用它来轻松模拟所有条件以无缝地测试权限。还可以进行断言,例如确保应用程序调用requestPermissions()。

答案 4 :(得分:1)

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

如果从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

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

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

Android Test Orchestrator计划在每次测试之间自动清除所有数据,但该功能目前仍然不存在。 I filed a bug you can vote up在测试之间进行自动清理。

答案 5 :(得分:1)

我遇到了同样的问题,并采用了以下解决方案(目前每次都运行良好)

创建gradle任务:

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

转到“运行/调试配置”,然后选择您的Android Instrumented测试。 在下面,您将有一个“启动前”选项。 点击加号,然后添加您的自定义gradle任务

Image

希望有帮助! 我一直在尝试为具有多种口味,因此具有多个程序包名称的项目找到一种可扩展的解决方案,但到目前为止,没有真正有效的方法。