我正在构建一个测试 apk,我希望该测试 apk 能够从外部文件读取一些配置值,而不必将该配置编译到 apk 文件中。
我在浓缩咖啡
TestRule
中有一个方法尝试执行此操作,但我似乎受到外部存储权限更改的阻碍。以下代码会导致 SDK 28 和 29 上出现权限错误,而在 SDK 30 上会出现安全异常
$myPackageNameHere 请求的权限 android.permission.MANAGE_EXTERNAL_STORAGE 不是可更改的权限类型
val instrumentation = InstrumentationRegistry.getInstrumentation()
val packageName = instrumentation.context.packageName
with(instrumentation.uiAutomation) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
grantRuntimePermission(packageName, Manifest.permission.MANAGE_EXTERNAL_STORAGE)
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
grantRuntimePermission(packageName, Manifest.permission.READ_EXTERNAL_STORAGE)
grantRuntimePermission(packageName, Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
}
val dir = Environment.getExternalStorageDirectory()
val configFile = File(dir, "test-config.json")
FileInputStream(configFile).use {
config = json.decodeFromStream(it)
}
我尝试获取测试上下文的外部文件目录,但它always为空(我尝试多次调用它,它没有帮助,仍然为空。我检查了安装状态,并且外部存储已安装。
instrumentation.context.getExternalFilesDir(null)
val dir = instrumentation.context.getExternalFilesDir(null)
我可以获取目标上下文的外部文件目录:
instrumentation.targetContext.getExternalFilesDir(null)
val dir = instrumentation.targetContext.getExternalFilesDir(null)
但是,我还使用带有
clearPackageData: true
的协调器,因此该目录被擦除,并且它似乎发生在我的测试实例化之前。所以该文件不存在 - 无论如何我都无法从我的测试中读取它!
我注意到这里数据存储用例的这一部分,它应该允许选择退出测试 - https://developer.android.com/training/data-storage/use-cases#opt-out-in-测试 - 但我不确定如何通过测试运行程序通过它。它建议使用它来写入测试数据,但我们有测试服务来在编排期间处理该数据 - 我需要read数据,而不是write数据。另外,看起来它也会影响正在测试的应用程序,这意味着这就是为什么我的测试上下文中的
getExternalFilesDir(null)
返回 null。
有什么办法可以做到这一点吗?或者我是否坚持将配置文件编译到测试 apk 中并像这样读取它:
this::class.java.classLoader?.getResource("test-config.json")?.openStream()?.use {
config = json.decodeFromStream(it)
}
正如您所注意到的,似乎无法通过 grantRuntimePermission()
请求
MANAGE_EXTERNAL_STORAGE。我发现授予此权限用于测试的唯一解决方案是通过 shell 命令。
创建您自己的规则:
public class GrantManageStoragePermissionRule implements TestRule {
@NonNull
@Override
public Statement apply(@NonNull Statement base, @NonNull Description description) {
return new RequestManageStoragePermStatement(base);
}
private static class RequestManageStoragePermStatement extends Statement {
private final Statement base;
public RequestManageStoragePermStatement(Statement base) {
this.base = base;
}
@Override
public void evaluate() throws Throwable {
ParcelFileDescriptor desc = getInstrumentation().getUiAutomation().executeShellCommand(
"appops set --uid "+ BuildConfig.APPLICATION_ID+" MANAGE_EXTERNAL_STORAGE allow");
desc.close();
base.evaluate();
}
}
}
并像这样使用它:
@Rule
public GrantManageStoragePermissionRule manageStoragePermRule = new GrantManageStoragePermissionRule();
但我怀疑这应该是适合您的用例的解决方案。仅仅为了测试而授予如此严格的权限可能会在其他测试中造成不必要的副作用。