Android Marshmallow引入的新权限方案要求在运行时检查特定权限,这意味着需要根据用户是拒绝还是允许访问来提供不同的流。
当我们使用Espresso在我们的应用上运行自动化的UI测试时,如何模拟或更新权限状态以测试不同的场景?
Android Marshmallow引入的新权限方案要求在运行时检查特定权限,这意味着需要根据用户是拒绝还是允许访问来提供不同的流。
当我们使用Espresso在我们的应用上运行自动化的UI测试时,如何模拟或更新权限状态以测试不同的场景?
Answers:
随着新版本的Android测试支持库1.0的发布,您可以在测试中使用GrantPermissionRule在开始任何测试之前授予权限。
@Rule public GrantPermissionRule permissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
Kotlin解决方案
@get:Rule var permissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION)
@get:Rule
必须使用以避免在此处出现java.lang.Exception: The @Rule 'permissionRule' must be public.
更多信息。
接受的答案实际上并没有测试权限对话框。它只是绕过它。因此,如果权限对话框由于某种原因而失败,则测试将给出错误的绿色。我鼓励实际上单击“授予权限”按钮以测试整个应用程序的行为。
看一下这个解决方案:
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
顺便说一下,由于这个答案很受欢迎,我们PermissionGranter
在Estapress和UiAutomator上方的工具Barista中添加了绿色工具测试:https ://github.com/SchibstedSpain/Barista对其进行了检验,因为我们将对其进行维护逐个发布。
当您的电话位于英语区域设置时,尝试使用这种静态方法:
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 ");
}
}
}
}
我在这里找到
您可以在运行测试之前授予权限,例如:
@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...
该过程被终止。
@org.junit.AfterClass
或@org.junit.BeforeClass
批注,您就应该能够使用相同的方法撤消权限
pm grand
工作后重新启动,这在测试中是不可能的
adb shell
测试套件中使用命令。关于单击对话框,Espresso应该能够自行处理。问题是,在运行测试并启用权限后,下次运行测试将失败,因为设置将保持不变并且该对话框将不会再次显示。
您可以通过在开始测试之前授予许可来轻松实现此目的。例如,如果您应该在测试运行期间使用相机,则可以按以下方式授予权限
@Before
public void grantPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
getInstrumentation().getUiAutomation().executeShellCommand(
"pm grant " + getTargetContext().getPackageName()
+ " android.permission.CAMERA");
}
}
浓缩咖啡更新
此单行代码立即授予在Grant方法中作为参数列出的所有权限。换句话说,该应用将被视为已授予权限-不再显示对话框
@Rule @JvmField
val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION)
和gradle
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/
如果您需要为单个测试或运行时设置权限,而不是规则,则可以使用以下权限:
PermissionRequester().apply {
addPermissions(android.Manifest.permission.RECORD_AUDIO)
requestPermissions()
}
例如
@Test
fun openWithGrantedPermission_NavigatesHome() {
launchFragmentInContainer<PermissionsFragment>().onFragment {
setViewNavController(it.requireView(), mockNavController)
PermissionRequester().apply {
addPermissions(android.Manifest.permission.RECORD_AUDIO)
requestPermissions()
}
}
verify {
mockNavController.navigate(R.id.action_permissionsFragment_to_homeFragment)
}
}
我已经实现了一个利用包装类,覆盖和构建变体配置的解决方案。解决方案的解释时间很长,可以在以下网址找到:https : //github.com/ahasbini/AndroidTestMockPermissionUtils。
现在还装在一个SDK,但主要的想法是重写的功能ContextWrapper.checkSelfPermission
和ActivityCompat.requestPermissions
进行操作,并返回模拟结果,将应用诱骗到要测试的不同场景中,例如:权限被拒绝,因此应用请求它并以授予结束允许。即使该应用程序一直都具有许可,也会发生这种情况,但是其想法是,该方法受到了覆盖实现的模拟结果的欺骗。
此外,该实现还有一个TestRule
被调用的PermissionRule
类,可以在测试类中使用它来轻松模拟所有条件以无缝测试权限。也可以进行断言,例如确保应用已调用requestPermissions()
。