running-tests-on-gradle-managed-devices について
Gradle Managed Devices で Android のインストルメンテーションテストを構成・実行するガイドです。再現可能なエミュレーター実行を求めるチーム向けに、デバイス構成、生成タスク、ATD イメージ、シャーディング、CI レポートを扱います。
主な機能
- 01Gradle で仮想デバイスを定義
- 02デバイス別・グループ別タスクの実行
- 03CI テストでの ATD イメージ利用
- 04インストルメンテーションテストの並列分割
- 05マネージドデバイスのレポート収集
活用シーン
- 01CI で定義済みデバイスのテストを実行
- 02複数の API レベルや端末構成を検証
- 03CI のエミュレーター起動負荷を軽減
- 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 がシステムイメージをダウンロードし、新しいエミュレーターを起動して androidTest を実行し、結果を収集して終了します。メリットは再現性です。CI でも各マシンでもまったく同じデバイスで実行でき、手動でエミュレーターを管理する必要がありません。このスキルでは、DSL、生成されるタスク、低コストな CI 向けの ATD イメージ、シャーディング、そして connectedAndroidTest や直接の am instrument と比べた GMD の位置づけを扱います(../../../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 でデバイスをまとめると、1 つのタスクでグループ内すべてのデバイスを対象にテストスイートを実行できます。
- 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")は、ヘッドレスでのテスト実行向けに簡素化されています。セットアップウィザードや UI の装飾がなく、サイズが小さく、起動が速く、メモリ使用量も少なくなっています。通常テストに必要となる Google API は(google-atdバリアントで)利用できますが、Play ストアは含まれません。テストで Play services や Play ストアの動作が本当に必要な場合に限り、フルイメージを使用してください。 -
5. 時間のかかるテストスイートをエミュレーターの複製に分散します。 GMD では、ドキュメントに記載されている Gradle プロパティ(例:
-Pandroid.experimental.androidTest.numManagedDeviceShards=N)を使って、管理対象デバイスを N 台複製し、テストを分割して並列実行できます。--max-concurrent-shardsを使うと、同時に実行する数を制限できます。テストの分散は、am instrument -e numShardsと同じく、テスト名のハッシュに基づいて振り分けられます。この機能に依存する前に、使用している AGP バージョンでの正確なプロパティ名を GMD のドキュメントで確認してください。 -
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を実行してマトリックスを 1 つのタスクにまとめます。全デバイスを網羅する場合は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 は、それらを実行する環境の 1 つです。
- developer.android.com/tools/adb — GMD を使用しない場合の低レベルな代替手段として、
adbとam instrumentについて説明しています。 - 関連スキル:
../../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— CI で@Previewのスクリーンショットを生成するために、マネージドデバイス(またはandroid-emulator-runner)を使用します。