关于 running-tests-on-gradle-managed-devices
这项技能介绍使用 Gradle Managed Devices 在构建中配置并运行 Android 仪器测试,面向需要可复现模拟器测试的 Android 团队。内容涵盖设备矩阵、自动生成任务、ATD 镜像、测试分片和 CI 报告。
主要功能
- 01在 Gradle 中声明虚拟设备
- 02运行设备与设备组测试任务
- 03使用 ATD 镜像运行 CI 测试
- 04并行分片仪器测试
- 05收集托管设备测试报告
适用场景
- 01在 CI 中运行固定设备配置的测试
- 02覆盖多个 API 级别或设备型号
- 03缩短 CI 模拟器启动开销
- 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(稳定版
managedDevicesDSL;旧版 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/localDevicesDSL、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截图。