在 CI 中使用存储权限进行 Android UI 测试

标签 android jenkins-pipeline ui-testing

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

当我在 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
}

我看到了一个短期解决方案,可以手动将我所有的媒体 Assets 复制到模拟器中。但这似乎不对,这应该可以自动化。

最佳答案

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

在我的 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 结尾。我认为需要在他们的每个 AndroidManifest 中定义权限,但事实证明,为您的 app AndroidManifest 定义权限只会自动提供对 Instrumentation 包也有相同的权限。

关于在 CI 中使用存储权限进行 Android UI 测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52976714/

相关文章:

android - 如何在 Android 上显示来自 URL 的图像

jenkins - 使用 jenkins 管道插件实现动态并行构建的想法

ios - Xcode UI 测试允许系统警报系列

groovy - 如何在 Groovy 中获取字符串每一行的第一个单词

ios - UITesting -> NavigationItem 的 titleView 中的 UISearchBar 返回 XCUIElement.Type other

unit-testing - Selenium 批判

java - 为什么我得到 "mergeCursor"对象而不是 "string"?

android - setType 的 Intent 不包括图像和视频,但包括其他所有内容

android - 将 sbt-assembly 用于 Newman,StackMob 的 Http 客户端库

jenkins - 多分支管道 Jenkins 作业与[ci跳过]