【问题标题】:Android UI Tests with Storage Permissions in CI在 CI 中使用存储权限进行 Android UI 测试
【发布时间】:2018-10-24 19:36:57
【问题描述】:

我想在 CI(Jenkins 流水线)中的项目上运行 UI 测试和单元测试。 UI 测试要求图像和视频位于测试设备/模拟器上。在 UI 测试中,我请求存储读/写访问权限,以便我可以将一些资产转储到下载文件夹中,然后在测试套件结束时删除它们。

当我在 Jenkins (mac) 上运行测试时,未授予权限,没有媒体传输,并且我的所有测试都失败了。

该项目包含一个应用模块和两个内部库模块。

流水线步骤

构建

sh "./gradlew clean assembleRelease"

单元测试

sh "./gradlew testReleaseUnitTest"

界面测试

sh "$ANDROID_HOME/emulator/emulator @my_sweet_emulator_name -no-boot-anim & $ANDROID_HOME/platform-tools/adb wait-for-device"
sh './gradlew connectedAndroidTest'

问题

1) CI 构建挂在隐式 assembleDebugAndroidTest 任务上

2) 如果我在计算机上的命令行上运行该任务,则会安装测试,但未授予读取/写入存储的权限,因此所有测试都因设备上没有任何预期内容而失败。

我尝试过的事情

  • 我尝试只测试发布版本,但这显示了相同的问题 2。testBuildType "release"
  • 我没有其他需要使用的权限

我如何授予权限

@RunWith(AndroidJUnit4::class)
class MyMediaClassTest {

    @Rule
    @JvmField
    val activityRule = ActivityTestRule(MainActivity::class.java)

    @Rule
    @JvmField
    val grantPermissionRule: GrantPermissionRule = GrantPermissionRule
            .grant(android.Manifest.permission.READ_EXTERNAL_STORAGE,
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
// tests and stuff
}

我看到了一种短期解决方案,可以将我的所有媒体资产手动复制到模拟器中。不过好像不太对,这个应该可以自动化吧。

【问题讨论】:

  • 您能否发布测试失败时显示的异常?您还确定可以在模拟器中创建文件吗?可能是在 sdcard/emulated 文件夹不可写的情况下创建了存储...尝试在模拟器中的 Chrome 中从网站下载文件以确保
  • @ahasbini 1) 由于设备上没有媒体,测试失败,因此此处的堆栈跟踪无济于事。 2)我能够手动将文件复制到设备(拖放),然后一切都“没问题”
  • 我已经尝试过您尝试的方式(拖放)并找到要复制到/sdcard/Downloads的文件。您是否能够确认文件正在被复制到模拟器中?使用命令adb shellcd /sdcard/Downloads' in order to confirm that the files are there using ls -la` 命令进行确认会很有帮助。
  • 是的,一旦我拖放到模拟器上,我就可以确认文件存在。但是,这不是我想要做的,这是一种解决方法。理想的解决方案是通过 UI 测试实现自动化。理想的步骤是:1)在测试之前授予权限并将媒体复制到模拟器。 2)运行测试。 3)从模拟器中删除媒体
  • 这看起来更像是复制文件的代码的问题。这就是堆栈跟踪和相关代码的原因。而不是@Rule @JvmField,我通常使用@get:Rule

标签: android jenkins-pipeline ui-testing


【解决方案1】:

它与我一起工作的方式是按照以下步骤操作:

在我的app 模块的AndroidManifest.xml 文件中添加了权限。

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

并已尝试执行以下检测的测试用例/类:

@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {

    @Rule
    @JvmField
    val grantPermissionRule: GrantPermissionRule = GrantPermissionRule
            .grant(android.Manifest.permission.READ_EXTERNAL_STORAGE,
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE)

    val rootDir = "/sdcard/"

    @Test
    fun testTargetContextPermission() {
        val targetContext = InstrumentationRegistry.getTargetContext()
        assertTrue("Not the target package",
                !targetContext.packageName.endsWith(".test"))
        assertTrue("Permissions not Granted", targetContext.checkSelfPermission(
                android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
                targetContext.checkSelfPermission(
                        android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
        val file = File(rootDir + "targetTest.txt")
        if (file.exists()) {
            file.delete()
        }
        assertTrue("File was not created", file.createNewFile())
        val sdcard = File(rootDir)
        assertTrue("sdcard is empty or file not found", sdcard.list().size != 0 &&
                Arrays.asList<String>(*sdcard.list()).contains("targetTest.txt"))
    }

    @Test
    fun testInstrumentationPermission() {
        val instrumentationContext = InstrumentationRegistry.getContext()
        assertTrue("Not the instrumentation package",
                instrumentationContext.packageName.endsWith(".test"))
        assertTrue("Permissions not Granted", instrumentationContext.checkSelfPermission(
                android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
                instrumentationContext.checkSelfPermission(
                        android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
        val file = File(rootDir + "instrumentationTest.txt")
        if (file.exists()) {
            file.delete()
        }
        assertTrue("File was not created", file.createNewFile())
        val sdcard = File(rootDir)
        assertTrue("sdcard is empty or file not found", sdcard.list().size != 0 &&
                Arrays.asList<String>(*sdcard.list()).contains("instrumentationTest.txt"))
    }
}

两个测试用例都成功返回。将rootDir 更改为"/" 后,测试失败,因为/ 目录是预期的只读目录。

拥有两个测试用例背后的想法是测试测试可以在运行时检索到的不同ContexttestTargetContextPermission 使用应用程序 Context没有它的包名称或应用程序 ID 以 .test 结尾。虽然testInstrumentationPermission 使用检测应用程序Context,但确实 的包名称或应用程序ID 以.test 结尾。我认为需要在他们的每个AndroidManifests 中定义权限,但事实证明,仅为您的app AndroidManifest 定义权限也会自动为 Instrumentation 包提供相同的权限。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-22
    相关资源
    最近更新 更多