mcpField
R
running-tests-on-gradle-managed-devices

running-tests-on-gradle-managed-devices

github.com/skydoves测试与质量33962 次安装22 周前更新
代码仓库

关于 running-tests-on-gradle-managed-devices

这项技能介绍使用 Gradle Managed Devices 在构建中配置并运行 Android 仪器测试,面向需要可复现模拟器测试的 Android 团队。内容涵盖设备矩阵、自动生成任务、ATD 镜像、测试分片和 CI 报告。

主要功能

  1. 01在 Gradle 中声明虚拟设备
  2. 02运行设备与设备组测试任务
  3. 03使用 ATD 镜像运行 CI 测试
  4. 04并行分片仪器测试
  5. 05收集托管设备测试报告

适用场景

  1. 01在 CI 中运行固定设备配置的测试
  2. 02覆盖多个 API 级别或设备型号
  3. 03缩短 CI 模拟器启动开销
  4. 04将慢速测试套件分片并行执行

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/skydoves/android-testing-skills --skill running-tests-on-gradle-managed-devices

安装后在 Claude Code 中输入/running-tests-on-gradle-managed-devices确认已加载。

详细介绍

在 Gradle 管理的设备上运行测试 — 由 Gradle 管理模拟器

Gradle 管理的设备(GMD)将模拟器纳入构建流程:你在 build.gradle.kts 中声明设备,然后运行 ./gradlew <device>DebugAndroidTest,Gradle 就会下载系统映像、启动一个全新的模拟器、运行 androidTest、收集结果并关闭模拟器。这样做的好处是可重复性——CI 和每台机器都会运行完全相同的设备,而且无需手动管理模拟器。本技能介绍 DSL、生成的任务、适用于低成本 CI 的 ATD 映像、分片,以及 GMD 与 connectedAndroidTest 和原始 am instrument 的区别(参见 ../../../adb/tests/running-instrumented-tests-via-adb/SKILL.md)。

何时使用此技能

  • 用户希望在 CI 中使用指定且可重复的模拟器运行插桩测试,而不想通过 adb 管理设备。
  • 用户提到 managedDevices、allDevicesCheck、ManagedVirtualDevice 或 pixel2api30DebugAndroidTest 之类的生成任务。
  • 用户希望将测试矩阵(API 级别/设备外形)纳入版本控制,而不是留在某人的本地 AVD 列表中。
  • CI 模拟器运行缓慢或不稳定,用户询问 ATD(“自动化测试设备”)映像。
  • 用户希望将耗时较长的插桩测试套件分片,分散到多个模拟器实例中运行。

何时不使用此技能

  • 用户希望在实体设备或已经运行的模拟器上运行测试——应使用 ./gradlew connectedAndroidTest / connectedDebugAndroidTest;GMD 用于由 Gradle 创建的模拟器。
  • 用户不通过 Gradle 而是直接调用运行器(adb shell am instrument -w -r …、通过 -e numShards 分片、配置 Test Orchestrator)——请使用 ../../../adb/tests/running-instrumented-tests-via-adb/SKILL.md 和 ../../../adb/automation/scripting-adb-for-ci/SKILL.md。
  • 用户正在选择 AndroidJUnit4 运行器或编写测试类本身——请使用 ../../runner/running-instrumented-tests-with-androidjunit4/SKILL.md。
  • 用户专门需要 Compose UI 测试——这类测试仍作为插桩测试运行;GMD 只是提供运行环境。请先参阅 ../../../compose/setup/setting-up-host-vs-device-tests/SKILL.md,了解主机与设备的选择。

先决条件

  • 支持 GMD 的 Android Gradle Plugin(稳定版 managedDevices DSL;旧版 AGP 曾以实验形式通过 android.testOptions.managedDevices 提供其中部分功能——请查阅与你的 AGP 版本对应的文档)。
  • 按常规配置好 androidTest:testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"、androidTestImplementation 依赖。GMD 改变的是测试的运行位置,而不是测试的编写方式。
  • 构建机器上有足够的磁盘空间,并配备可用的 KVM/HAXM/虚拟机监控程序(CI 运行器需要启用 KVM)——GMD 会启动真正的模拟器。
  • 接受 GMD 下载的系统映像许可(运行 sdkmanager --licenses,或在 CI 设置中接受许可)。

工作流

  • 1. 声明受管理的设备。 在模块的 build.gradle.kts 中:
android {
    testOptions {
        managedDevices {
            localDevices {
                create("pixel6api34") {
                    device = "Pixel 6"          // a Device Manager profile name
                    apiLevel = 34
                    systemImageSource = "aosp"  // "aosp" | "google" | "google_apis_playstore" | "aosp-atd" | "google-atd"
                }
                create("pixel2api30") {
                    device = "Pixel 2"
                    apiLevel = 30
                    systemImageSource = "aosp-atd"  // ATD: stripped-down, headless, faster — good for CI
                }
            }
            groups {
                create("ciMatrix") {
                    targetDevices.add(localDevices["pixel6api34"])
                    targetDevices.add(localDevices["pixel2api30"])
                }
            }
        }
    }
}

每个 create("name") { … } 都是一个 ManagedVirtualDevice:device 是 Device Manager 配置文件,apiLevel 是系统映像 API 级别,systemImageSource 指定映像系列。如果需要强制使用 64 位映像,请使用 require64Bit = true。group 会将多个设备组合起来,让一个任务在所有设备上运行测试套件。

  • 2. 运行生成的任务。 GMD 会为每台设备、每个组以及所有设备生成一个任务:
./gradlew pixel6api34DebugAndroidTest          # androidTest on one managed device
./gradlew ciMatrixGroupDebugAndroidTest        # androidTest on every device in the "ciMatrix" group
./gradlew allDevicesCheck                      # androidTest on ALL managed devices defined in the project

变体命名遵循构建变体(…DebugAndroidTest、…ReleaseAndroidTest,如果有产品风味,还会加上风味前缀)。这些任务会:在系统映像缺失时下载它,启动全新的模拟器,安装应用和测试 APK,运行测试套件,写入结果,然后关闭模拟器——无需你手动安排 adb 操作。

  • 3. 查看结果。 每台设备的 HTML 报告位于 app/build/reports/androidTests/managedDevice/<deviceName>/(运行组或 allDevicesCheck 时,还会生成汇总报告);机器可读结果位于 app/build/outputs/androidTest-results/managedDevice/;测试通过 TestStorage 输出的内容及其他测试输出位于 app/build/outputs/managed_device_android_test_additional_output/<deviceName>/。将这些路径配置为 CI 构建产物归档路径。

  • 4. 在 CI 中优先使用 ATD 映像。 Automated Test Device 映像(systemImageSource = "aosp-atd" 或 "google-atd")经过精简,适合无头测试执行——没有设置向导和界面上的多余功能,体积更小、启动更快、内存占用更低。它们保留了测试通常需要的 Google API(google-atd 变体),但不包含 Play Store。只有当测试确实需要 Play 服务或 Play Store 行为时,才使用完整映像。

  • 5. 将运行缓慢的测试套件分片到多个模拟器副本上。 GMD 可以在 N 个受管理设备副本上并行运行测试套件,并在这些设备间拆分测试;可通过文档中说明的 Gradle 属性(例如 -Pandroid.experimental.androidTest.numManagedDeviceShards=N)以及 --max-concurrent-shards 限制同时运行的数量。测试会按名称哈希分桶,与 am instrument -e numShards 的方式相同。使用前请查看 GMD 文档,确认你的 AGP 版本对应的属性名称。

  • 6. 配置 CI。 GMD 任务是普通 Gradle 任务;CI 只需启用 KVM 并接受许可证:

# .github/workflows/instrumented-tests.yml
jobs:
  androidTest:
    runs-on: ubuntu-latest
    timeout-minutes: 45
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with: { distribution: zulu, java-version: 17 }
      - name: Enable KVM
        run: |
          echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
          sudo udevadm control --reload-rules && sudo udevadm trigger --name-match=kvm
      - run: ./gradlew pixel2api30DebugAndroidTest   # ATD device declared above
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: androidTest-report
          path: |
            app/build/reports/androidTests/managedDevice/
            app/build/outputs/managed_device_android_test_additional_output/

默认情况下,模拟器以无头模式运行。(如果需要在本地查看模拟器——例如调试 UI 测试——请参阅 GMD 文档,了解显示模拟器窗口的选项;在 CI 中,该选项处于关闭状态。)

模式

模式:在 CI 中使用 connectedAndroidTest,并手动管理模拟器
# WRONG — boot an emulator with adb/avdmanager scripting, then connectedAndroidTest
- run: |
    avdmanager create avd -n ci -k 'system-images;android-30;default;x86_64'
    emulator -avd ci -no-window -no-snapshot &
    adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done'
    ./gradlew connectedDebugAndroidTest
# WRONG because: every repo reinvents this, the device definition is not in version control, and
# "works on my machine" diverges from CI. GMD makes the device a build input, provisioned identically everywhere.
// RIGHT — declare it once in build.gradle.kts; CI just runs the task
android { testOptions { managedDevices { localDevices { create("ciDevice") {
    device = "Pixel 2"; apiLevel = 30; systemImageSource = "aosp-atd"
} } } } }
// CI:  ./gradlew ciDeviceDebugAndroidTest
模式:ATD 已够用,却在 CI 中使用完整系统映像
// WRONG
create("ciDevice") { device = "Pixel 6"; apiLevel = 34; systemImageSource = "google_apis_playstore" }
// WRONG because: the Play Store image is the heaviest one — slow to download, slow to boot, more RAM —
// and the test suite does not exercise Play Store behavior. CI minutes burn for nothing.
// RIGHT — ATD: headless, stripped, keeps the Google APIs tests usually need
create("ciDevice") { device = "Pixel 6"; apiLevel = 34; systemImageSource = "google-atd" }
模式:认为 GMD 任务的 $? 是唯一的判断信号
# WRONG — assume a green exit code means everything passed and stop there
./gradlew allDevicesCheck && echo "all good"
# WRONG because: Gradle does fail the build on test failures here (unlike raw `am instrument`), but a
# device that fails to provision, an OOM-killed emulator, or a flaky boot can also fail the task with
# nothing useful on stdout. Always archive app/build/reports/androidTests/managedDevice/ so a failure is diagnosable.
# RIGHT — keep the reports regardless of outcome
- run: ./gradlew allDevicesCheck
- uses: actions/upload-artifact@v4
  if: always()
  with: { name: androidTest-report, path: app/build/reports/androidTests/managedDevice/ }

强制规则

  • 必须在版本控制中通过 android.testOptions.managedDevices 声明托管设备——测试设备矩阵是构建输入,而不是每台机器各自配置的 AVD。
  • 必须在 CI 中优先使用 ATD 镜像(aosp-atd / google-atd);只有测试需要 GMS / Play Store 行为时,才使用完整镜像或 Play Store 镜像。
  • 必须在 CI 运行器上启用 KVM(或平台虚拟机监控程序),并在调用 GMD 任务前接受 SDK 许可——否则模拟器无法启动。
  • 必须在每次运行时归档 app/build/reports/androidTests/managedDevice/(以及 …/managed_device_android_test_additional_output/),无论成功还是失败,以便诊断故障。
  • 不得在 GMD 适用时手动编写 avdmanager/emulator/adb wait-for-device 脚本,然后运行 connectedAndroidTest——设备配置、启动和关闭都由 GMD 负责。
  • 不得假设托管设备任务的退出代码能区分测试失败与基础设施故障;请查看 HTML 报告。
  • **建议:**对设备分组(groups { create("ciMatrix") { … } }),并运行 ciMatrixGroupDebugAndroidTest,将矩阵作为一个任务执行;完整测试则使用 allDevicesCheck。
  • **建议:**使用文档中说明的 numManagedDeviceShards 属性和 --max-concurrent-shards 对耗时较长的测试套件进行分片,而不是手动拆分测试套件。

验证

  • ./gradlew tasks --all | grep -i AndroidTest 列出生成的 <deviceName>DebugAndroidTest、<groupName>GroupDebugAndroidTest 和 allDevicesCheck 任务。
  • ./gradlew <deviceName>DebugAndroidTest 启动模拟器、运行 androidTest,并生成 app/build/reports/androidTests/managedDevice/<deviceName>/index.html。
  • 设备定义位于 build.gradle.kts 中(已提交),且不依赖本地 AVD。
  • CI 在启用 KVM 的情况下运行 GMD 任务,并通过 if: always() 上传托管设备报告目录。
  • CI 设备使用 ATD 镜像(*-atd),除非特定测试说明了需要完整镜像或 Play Store 镜像的原因。

参考资料

  • developer.android.com/studio/test/gradle-managed-devices — managedDevices / localDevices DSL、ManagedVirtualDevice(device、apiLevel、systemImageSource、require64Bit)、设备 groups、生成的 <device>…AndroidTest / <group>Group…AndroidTest / allDevicesCheck 任务、ATD 镜像、分片(numManagedDeviceShards、--max-concurrent-shards)、报告和输出位置,以及显示模拟器窗口的方法。
  • developer.android.com/studio/test/advanced-test-setup — testOptions.animationsDisabled、Test Orchestrator,以及同样适用于 GMD 运行的分片说明。
  • developer.android.com/training/testing/instrumented-tests — 插桩测试基础知识;GMD 是运行这类测试的一种执行环境。
  • developer.android.com/tools/adb — adb 和 am instrument,适用于不使用 GMD 时的底层替代方案。
  • 同级技能:../../runner/running-instrumented-tests-with-androidjunit4/SKILL.md — 测试使用的 AndroidJUnit4 运行器,无论测试在哪里执行。
  • 跨集合:../../../adb/tests/running-instrumented-tests-via-adb/SKILL.md — 不使用 Gradle,通过 adb shell am instrument -w -r 运行相同的测试。
  • 跨集合:../../../adb/automation/scripting-adb-for-ci/SKILL.md — CI Bash 习惯用法、通过 -e numShards 进行分片、Test Orchestrator 配置,以及失败时捕获信息。
  • 跨集合:../../../compose/preview/capturing-preview-screenshots-in-ci/SKILL.md — 使用托管设备(或 android-emulator-runner)在 CI 中渲染 @Preview 截图。

评论

支持 Markdown