How to manage Runtime permissions android marshmallow espresso tests

后端 未结 12 866
孤独总比滥情好
孤独总比滥情好 2020-12-05 02:33

I\'m using espresso for testing but sometimes I try to get an image form external storage and with marshmallow I need a Runtime permission otherwise there will be an Excepti

相关标签:
12条回答
  • 2020-12-05 03:27

    You can create an Android gradle task to grant permission:

    android.applicationVariants.all { variant ->
        def applicationId = variant.applicationId
        def adb = android.getAdbExe().toString()
        def variantName = variant.name.capitalize()
        def grantPermissionTask = tasks.create("grant${variantName}Permissions") << {
            "${adb} devices".execute().text.eachLine {
                if (it.endsWith("device")){
                    def device = it.split()[0]
                    println "Granting permissions on devices ${device}"
                    "${adb} -s ${device} shell pm grant ${applicationId} android.permission.CAMERA".execute()
                    "${adb} -s ${device} shell pm grant ${applicationId} android.permission.ACCESS_FINE_LOCATION".execute()
                }
            }
        }
    }
    

    And this is the command to run the task: gradle grantDebugPermissions

    0 讨论(0)
  • 2020-12-05 03:30

    There is GrantPermissionRule in Android Testing Support Library, that you can use in your tests to grant a permission before starting any tests.

    @Rule public GrantPermissionRule permissionRule = GrantPermissionRule.grant(android.Manifest.permission.CAMERA);
    
    0 讨论(0)
  • 2020-12-05 03:30
        android.support.test.uiautomator.UiDevice mDevice;
    
     @Before
        public void setUp() throws Exception {
            mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
        }
    
    @Test
        public void testMainActivityScreenshots() {
                   allowPermissionsIfNeeded();//allowPermissions on Activity
    }
    
       private void allowPermissionsIfNeeded()  {
            if (Build.VERSION.SDK_INT >= 23) {
                UiObject allowPermissions = mDevice.findObject(
                        new UiSelector().className("android.widget.Button")
                        .resourceId("com.android.packageinstaller:id/permission_allow_button"));// get allow_button Button by id , because on another device languages it is not "Allow"
                if (allowPermissions.exists()) {
                    try {
                        allowPermissions.click();
                        allowPermissionsIfNeeded();//allow second Permission
                    } catch (UiObjectNotFoundException e) {
                        Timber.e(e, "There is no permissions dialog to interact with ");
                    }
                }
            }
        }
    
    0 讨论(0)
  • 2020-12-05 03:32

    UPDATE! Now you can use Rule from Android Testing Support Library

    It is more proper to use than custom rules.

    Outdated answer:

    You can add test rule to reuse code and add more flexibility:

    /**
     * This rule adds selected permissions to test app
     */
    
    public class PermissionsRule implements TestRule {
    
        private final String[] permissions;
    
        public PermissionsRule(String[] permissions) {
            this.permissions = permissions;
        }
    
        @Override
        public Statement apply(final Statement base, Description description) {
            return new Statement() {
                @Override
                public void evaluate() throws Throwable {
    
                    allowPermissions();
    
                    base.evaluate();
    
                    revokePermissions();
                }
            };
        }
    
        private void allowPermissions() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                for (String permission : permissions) {
                    InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
                            "pm grant " + InstrumentationRegistry.getTargetContext().getPackageName()
                                    + " " + permission);
                }
            }
        }
    
        private void revokePermissions() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                for (String permission : permissions) {
                    InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
                            "pm revoke " + InstrumentationRegistry.getTargetContext().getPackageName()
                                    + " " + permission);
                }
            }
        }
    }
    

    After that you can use this rule in your test classes:

    @Rule
    public final PermissionsRule permissionsRule = new PermissionsRule(
    new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS});
    

    Keep in mind:

    1. Rule does not affect on @Before methods because all rules are executed after that
    2. executeShellCommand is asynchronous and if you need accepted permissions right after test started consider adding some delay
    0 讨论(0)
  • 2020-12-05 03:32

    You can use GrantPermissionRule. This rule will grant all the requested runtime permissions for all test methods in that test class.

    @Rule 
    public GrantPermissionRule mRuntimePermissionRule
                = GrantPermissionRule.grant(Manifest.permission.READ_PHONE_STATE);
    
    0 讨论(0)
  • 2020-12-05 03:32

    You can achieve this easily by granting permission before starting the test. For example if you are supposed to use camera during the test run, you can grant permission as follows

    @Before
    public void grantPhonePermission() {
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            getInstrumentation().getUiAutomation().executeShellCommand(
                    "pm grant " + getTargetContext().getPackageName()
                            + " android.permission.CAMERA");
        }
    }
    
    0 讨论(0)
提交回复
热议问题