Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DroidKaigi 2022: Gradle Managed Virtual Devicesで変化するエミュレータ活用術

DroidKaigi 2022: Gradle Managed Virtual Devicesで変化するエミュレータ活用術

DroidKaigi 2022のセッション「Gradle Managed Virtual Devicesで変化するエミュレータ活用術」の発表資料です。

新しく導入されたGradle Managed Virtual Devices機能はどのようなものなのか、それによってエミュレータの使い方がどのように変化してくのか紹介します。
また、AGPの実装を調べて判明した内容を元に、Gradle Managed Virtual Devicesを活用する際に直面しがちなトラブルの解決方法も合わせて紹介します。

TOYAMA Sumio

October 05, 2022
Tweet

More Decks by TOYAMA Sumio

Other Decks in Programming

Transcript

  1. Gradle Managed Virtual Devices
    で変化するエミュレータ活⽤術
    2022.10.05
    TOYAMA Sumio (sumio_tym)
    1

    View Slide

  2. ⾃⼰紹介
    p ⽒名: 外⼭ 純⽣ (TOYAMA Sumio)
    @sumio_tym (Twitter) / @sumio (GitHub)
    p 所属: DeNA SWET第⼆グループ
    (Software Engineer in Test)
    p 業務内容: 主にAndroidにおける
    品質のボトルネック解決
    p その他: 「Androidテスト全書」執筆
    https://peaks.cc/sumio_tym/android_testing
    2

    View Slide

  3. お話しすること
    Gradleでエミュレータ作成〜テスト実⾏を実現する
    Gradle Managed (Virtual) Devices (GMD)について説明します
    p GMDとはどんな機能?
    p GMDの⽅が便利なのはどんなケース?
    p GMDで実⾏に失敗したらどうデバッグする?
    3
    公式な⾔及では「Gradle Managed Virtual Devices」と「Gradle Managed Devices」
    の呼称が混在していますが、以降ではAndroid Developersサイトで使われ始めた後者の
    呼称を使います

    View Slide

  4. Agenda
    1. GMD (Gradle Managed Devices)の使い⽅
    2. Androidエミュレータについておさらい
    3. GMDの困るところに対応する
    4. テストの種類別GMD活⽤シーン
    5. CIで動かすときのポイント
    6. まとめ
    4

    View Slide

  5. Agenda
    5
    1. GMD (Gradle Managed Devices)の使い⽅
    2. Androidエミュレータについておさらい
    3. GMDの困るところに対応する
    4. テストの種類別GMD活⽤シーン
    5. CIで動かすときのポイント
    6. まとめ

    View Slide

  6. GMD (Gradle Managed Devices)とは
    p AGP (Android Gradle Plugin)の新機能
    p 7.3.0よりstable (7.2では動かない機能あり)
    p build.gradleにエミュレータ種別を書いておけば、
    AVD作成からテスト実⾏までGradleがやってくれる
    (AVD: Android Virtual Device)
    6
    AVD作成 エミュレータ起動 テスト実⾏
    アプリ消去
    エミュレータ終了
    テストレポート作成

    View Slide

  7. (参考) バージョンの関係
    p Android Studioも使う場合、Stable版以外ではバージョン
    判定がシビアなので注意が必要
    7
    AGP Gradle (Android Studio)
    7.2.2 7.3.3+ Chipmunk | 2021.2.1 Patch 2
    7.3.0 7.4+ Dolphin | 2021.3.1
    7.4.0-beta02 7.5+ Electric Eel | 2022.1.1 Beta 1
    8.0.0-alpha02 7.5+ Flamingo | 2022.2.1 Canary 2
    ※2022.10.04現在の、メジャーバージョンごとの最新版

    View Slide

  8. build.gradle (デバイスの定義)
    8
    android { testOptions { managedDevices {
    devices {
    pixel5api33 (ManagedVirtualDevice) {
    device = "Pixel 5"
    apiLevel = 33
    systemImageSource = "google"
    require64Bit = false
    }
    ...
    }}}}

    View Slide

  9. build.gradle (デバイスの定義)
    9
    android { testOptions { managedDevices {
    devices {
    pixel5api33 (ManagedVirtualDevice) {
    device = "Pixel 5"
    apiLevel = 33
    systemImageSource = "google"
    require64Bit = false
    }
    ...
    }}}}
    デバイス名(適当な名前をつける)
    Device Profile
    システムイメージ
    x86_64イメージを
    強制的に使うかどうか

    View Slide

  10. systemImageSourceに指定できる値
    10
    従前のシステムイメージ ATD (Automated Test Device)
    (API Level 30, 31のみ)
    無印(AOSP) "aosp" "aosp-atd"
    Google APIs "google" "google-atd"
    Google Play
    "google_apis_playstore"
    (AGP 7.3+のみ)
    N/A
    ※ATD: Instrumented Test⽤途に最適化された軽量版システムイメージ。
    ハードウェアレンダリングが無効化されていたり、
    テストで使わなさそうなアプリやサービスが削除・無効化されている
    ※ATDで削除されているものの詳細は
    https://d.android.com/studio/test/gradle-managed-devices 参照

    View Slide

  11. build.gradle (複数個のデバイス定義)
    11
    android { testOptions { managedDevices {
    devices {
    pixel5api33 (ManagedVirtualDevice) { ... }
    pixel5api31 (ManagedVirtualDevice) { ... }
    pixel2api33 (ManagedVirtualDevice) { ... }
    }
    }}}

    View Slide

  12. android { testOptions { managedDevices {
    devices {
    pixel5api33 (ManagedVirtualDevice) { ... }
    pixel5api31 (ManagedVirtualDevice) { ... }
    pixel2api33 (ManagedVirtualDevice) { ... }
    }
    }}}
    build.gradle (複数個のデバイス定義)
    12
    複数個のデバイス定義を宣⾔できる

    View Slide

  13. build.gradle (デバイスグループ)
    13
    devices {
    pixel5api33 (ManagedVirtualDevice) { ... }
    pixel5api31 (ManagedVirtualDevice) { ... }
    pixel2api33 (ManagedVirtualDevice) { ... } }
    deviceGroups {
    pixel5 {
    targetDevices.add(devices.pixel5api33)
    targetDevices.add(devices.pixel5api31) }
    }
    }

    View Slide

  14. build.gradle (デバイスグループ)
    14
    devices {
    pixel5api33 (ManagedVirtualDevice) { ... }
    pixel5api31 (ManagedVirtualDevice) { ... }
    pixel2api33 (ManagedVirtualDevice) { ... } }
    deviceGroups {
    pixel5 {
    targetDevices.add(devices.pixel5api33)
    targetDevices.add(devices.pixel5api31) }
    }
    }
    デバイスグループ名 (適当な名前を付ける)

    View Slide

  15. 新しく作られるGradleタスク(基本的なもの)
    p pixel5api33DebugAndroidTest
    ( {デバイス名}{バリアント}AndroidTest )
    p {デバイス名}に対応するエミュレータを起動し、
    Instrumented Testを実⾏する
    p pixel5GroupDebugAndroidTest
    ( {デバイスグループ名}Group{バリアント}AndroidTest )
    p {デバイスグループ名}の各デバイスについて、対応するエミュレー
    タを起動し、Instrumented Testを実⾏する
    15

    View Slide

  16. 新しく作られるGradleタスク(その他①)
    p pixel5api33Setup ( {デバイス名}Setup )
    p {デバイス名}に対応するAVDが無ければ新しく作り、
    起動⾼速化のためにSnapshot(エミュレータのメモリなど)を保存する
    p {デバイス名}{バリアント}AndroidTestなどテスト実⾏時に呼ばれる
    p 時々このタスクだけ実⾏したくなることがある
    p cleanManagedDevices
    p この仕組みで作られたAVDを全部消す
    p 実⾏注意!!
    16

    View Slide

  17. 新しく作られるGradleタスク (その他②)
    p allDevicesDebugAndroidTest
    p build.gradleで宣⾔された全AVDについてテストする
    p デバイスグループを宣⾔しなくても使える
    p createManagedDeviceDebugAndroidTestCoverageReport
    p 全AVDについてテスト → カバレッジレポート出⼒
    (設定 testCoverageEnabled true が必要)
    17

    View Slide

  18. テストレポート・ログ
    p app/build/outputs/androidTest-results/managedDevice/
    flavors/{フレーバー名}/{デバイス名}/
    p JUnit互換テスト結果XML
    p ログ (logcat・adbなどの実⾏コマンドログ)
    p app/build/reports/androidTests/managedDevice/
    flavors/{フレーバー名}/{デバイス名}/
    p HTML形式のテスト結果レポート
    18

    View Slide

  19. AVDの保存場所
    GMDが作るAVDは隠されている
    p Android StudioのDevice Managerで作るAVD:
    $HOME/.android/avd/
    p GMDが作るAVD (AGP 7.3+):
    $HOME/.android/avd/gradle-managed
    p GMDが作るAVD (AGP 7.2.x):
    $HOME/.android/gradle/avd/
    19

    View Slide

  20. ここまでのまとめ
    p AVD作成時に指定できる項⽬は多くない。
    Device Profile、APIレベル、システムイメージのみ
    p 複数のAVDに対して、まとめてテストできる機能がある
    (デバイスグループ)
    p AVD作成→エミュレータ起動→テスト実⾏→レポート作成
    までいっぺんに実⾏するGradleタスクが使えるようになる
    p GMDによって作られたAVDは隠されている
    20

    View Slide

  21. GMDの嬉しいところ
    p build.gradleに書けばGradleが全部やってくれる
    p AVDの作成をGUIで操作しなくてOK
    p エミュレータ使ったテストのCI上での実⾏が簡単に
    p avdmanager create avdとか知らなくてOK
    p エミュレータの起動・終了を管理しなくてOK
    p adb wait-for-deviceなど・・
    21

    View Slide

  22. GMDの困るところ
    p テスト実⾏中の画⾯が⾒えない
    p アプリが起動しているかどうかすら分からない
    p AVD作成時のカスタマイズ項⽬が貧弱
    p せめて⽇本語の環境で動かしたい
    p RAMサイズ、ストレージサイズくらいは変更したい!
    p テストが終わるとapkがアンインストールされる
    p テスト実⾏中に作られたファイルも消えてしまう・・
    p テストに失敗したときのデバッグが難しい
    22

    View Slide

  23. 困るところは⾊々あるけれど・・・
    p いくつかの点は運⽤を⼯夫することで解決できる
    p ⼯夫のためにはAndroidエミュレータについて
    少し深い知識が必要
    詳しい説明の前に
    Androidエミュレータについて少しおさらいします
    23

    View Slide

  24. Agenda
    24
    1. GMD (Gradle Managed Devices)の使い⽅
    2. Androidエミュレータについておさらい
    3. GMDの困るところに対応する
    4. テストの種類別GMD活⽤シーン
    5. CIで動かすときのポイント
    6. まとめ

    View Slide

  25. 普段の開発で利⽤しているエミュレータ
    Android StudioのDevice ManagerからAVDを選んで起動
    25

    View Slide

  26. CLIでエミュレータを起動する①
    p コマンドの場所
    $ANDROID_HOME/emulator/emulator
    ($ANDROID_HOME/tools/emulatorは使わない)
    26

    View Slide

  27. CLIでエミュレータを起動する②
    p AVD名⼀覧表⽰
    emulator -list-avds
    p AVD名を指定してエミュレータ起動
    emulator -avd {AVD名}
    27
    この⽅法で表⽰・起動できるのは
    Android Studioで作ったAVDのみ
    ($HOME/.android/avd/に保存されているもの)

    View Slide

  28. CLIでエミュレータを起動する③
    環境変数ANDROID_AVD_HOMEで
    AVDの保存・検索ディレクトリを変更できる
    p {AVD保存場所}にあるAVD名の⼀覧表⽰
    env ANDROID_AVD_HOME={AVD保存場所} emulator -list-avds
    p {AVD保存場所}にあるAVD名を指定してエミュレータ起動
    env ANDROID_AVD_HOME={AVD保存場所} emulator –avd {AVD名}
    28

    View Slide

  29. AVDのファイル構成 (主要なもののみ)
    29
    ├── Pixel_3a_API_29.avd/
    │ ├── hardware-qemu.ini
    │ ├── config.ini
    │ ├── encryptionkey.img, encryptionkey.img.qcow2
    │ ├── cache.img, cache.img.qcow2
    │ ├── userdata-qemu.img, userdata-qemu.img.qcow2
    │ ├── userdata.img
    │ ├── ...
    └── Pixel_3a_API_29.ini
    ハードウェア・AVDの設定
    ディスクイメージ

    View Slide

  30. ここまでのまとめ
    p emulatorコマンドでCLIでもエミュレータを起動できる
    p コマンドサーチパス間違わないように注意
    p 環境変数ANDROID_AVD_HOMEを設定すれば
    標準以外の場所に保存されたAVDも参照できる
    p 保存されたAVDには、AVDの設定内容やディスクイメージ
    が格納されている
    30

    View Slide

  31. Agenda
    31
    1. GMD (Gradle Managed Devices)の使い⽅
    2. Androidエミュレータについておさらい
    3. GMDの困るところに対応する
    4. テストの種類別GMD活⽤シーン
    5. CIで動かすときのポイント
    6. まとめ

    View Slide

  32. GMDの困るところ (再掲)
    32
    p テスト実⾏中の画⾯が⾒えない
    p アプリが起動しているかどうかすら分からない
    p AVD作成時のカスタマイズ項⽬が貧弱
    p せめて⽇本語の環境で動かしたい
    p RAMサイズ、ストレージサイズくらいは変更したい!
    p テストが終わるとapkがアンインストールされる
    p テスト実⾏中に作られたファイルも消えてしまう・・
    p テストに失敗したときのデバッグが難しい

    View Slide

  33. 困り事の解決①
    33
    p テスト実⾏中の画⾯が⾒えない
    p アプリが起動しているかどうかすら分からない
    画⾯を表⽰しながら
    テストを実⾏する

    View Slide

  34. 画⾯を表⽰しながらテストを実⾏する
    p --enable-displayオプションを使う
    p 知っておくと便利なコマンド
    p Gradleタスクに使えるオプションがわかる
    ./gradlew -q help --task {タスク名}
    34
    ./gradlew pixel5api33DebugAndroidTest --enable-display

    View Slide

  35. 困り事の解決②
    35
    p AVD作成時のカスタマイズ項⽬が貧弱
    p せめて⽇本語の環境で動かしたい
    別アプリの助けを借りて
    ⾔語設定を変更する

    View Slide

  36. 別アプリの助けを借りて⾔語設定を変更する ①
    io.appium.settingsを使う(https://github.com/appium/io.appium.settings)
    p インストール(npm)
    npm i io.appium.settings
    p app/build.gradle
    36
    dependencies {
    androidTestUtil
    files('../node_modules/io.appium.settings/apks/settings
    _apk-debug.apk')
    }
    テスト実⾏時に、指定されたapkを
    パーミッションをgrantした状態で
    インストールしてくれる

    View Slide

  37. 別アプリの助けを借りて⾔語設定を変更する ②
    37
    class LocaleChangeListener : RunListener() {
    override fun testRunStarted(desc: Description?) {
    val uiAutomation =
    InstrumentationRegistry.getInstrumentation().uiAutomation
    val fd = uiAutomation.executeShellCommand("...")
    // 標準出⼒を全部捨てる
    }}
    p JUnit4のRunListenerを使って最初のテスト開始前に以下を実⾏する
    am broadcast -a io.appium.settings.locale
    -n io.appium.settings/.receivers.LocaleSettingReceiver
    --es lang {⾔語} --es country {地域}

    View Slide

  38. 別アプリの助けを借りて⾔語設定を変更する ②
    38
    class LocaleChangeListener : RunListener() {
    override fun testRunStarted(desc: Description?) {
    val uiAutomation =
    InstrumentationRegistry.getInstrumentation().uiAutomation
    val fd = uiAutomation.executeShellCommand("...")
    // 標準出⼒を全部捨てる
    }}
    p JUnit4のRunListenerを使って最初のテスト開始前に以下を実⾏する
    am broadcast -a io.appium.settings.locale
    -n io.appium.settings/.receivers.LocaleSettingReceiver
    --es lang {⾔語} --es country {地域}

    View Slide

  39. 別アプリの助けを借りて⾔語設定を変更する ②
    39
    class LocaleChangeListener : RunListener() {
    override fun testRunStarted(desc: Description?) {
    val uiAutomation =
    InstrumentationRegistry.getInstrumentation().uiAutomation
    val fd = uiAutomation.executeShellCommand("...")
    // 標準出⼒を全部捨てる
    }}
    テストコードから
    シェルコマンドを実⾏できる
    p JUnit4のRunListenerを使って最初のテスト開始前に以下を実⾏する
    am broadcast -a io.appium.settings.locale
    -n io.appium.settings/.receivers.LocaleSettingReceiver
    --es lang {⾔語} --es country {地域}

    View Slide

  40. 別アプリの助けを借りて⾔語設定を変更する ③
    p build.gradleでRunListener実装を登録する
    40
    android {
    defaultConfig {
    testInstrumentationRunnerArgument(
    "listener",
    "com.example.gmd.LocaleChangeListener"
    )
    }
    }
    • RunListener実装のクラス名を書く
    • 複数登録する場合はコンマ(,)区切り

    View Slide

  41. 困り事の解決③
    41
    p AVD作成時のカスタマイズ項⽬が貧弱
    p RAMサイズ、ストレージサイズくらいは変更したい!
    GMDで作られた
    AVDの設定を変える

    View Slide

  42. GMDで作られたAVDの設定を変える
    p GMDで作られたAVDのconfig.iniなどを変更する
    場所: $HOME/.android/avd/gradle-managed/{AVD名}.avd/
    p ディスクサイズ変更: disk.dataPartition.size=6g (config.ini)
    p etc.
    p 何を変更すれば良いか知りたいとき
    p hardware-properties.iniに詳しく定義されている
    https://bit.ly/3SXgisv (android.googlesource.com)
    42

    View Slide

  43. 困り事の解決④
    43
    p テストが終わるとapkがアンインストールされる
    p テスト実⾏中に作られたファイルも消えてしまう・・
    テスト終了時にファイル
    を取り出す

    View Slide

  44. テスト終了時にファイルを取り出す①
    p 隠しオプションadditionalTestOutputDirを使う
    44
    android {
    defaultConfig {
    testInstrumentationRunnerArgument(
    "additionalTestOutputDir",
    "/sdcard/Android/media/com.example.gmd/result"
    )
    }
    }
    ファイルを取り出したい
    (エミュレータ上の)ディレクトリ

    View Slide

  45. テスト終了時にファイルを取り出す②
    p 取り出された(pullされた)ファイルの保存先
    p AGP 8.0未満: app/build/outputs/
    managed_device_android_test_additional_output
    p AGP 8.0以上: app/build/intermediates/
    managed_device_android_test_additional_output
    p 引数に指定できるディレクトリについての注意
    p Scoped Storageが有効なOSでは
    /sdcard/Android/media/{アプリケーションID}/
    から始まるディレクトリしか受け付けない
    (それ以外に保存されたファイルは取り出せない)
    45

    View Slide

  46. 困り事の解決⑤
    46
    p テストが終わるとapkがアンインストールされる
    p テストに失敗したときのデバッグが難しい
    予めエミュレータを起動した
    状態でテストを動かす

    View Slide

  47. エミュレータを起動した状態でテストを動かす①
    p 予めGMDが作成したAVDでエミュレータを起動しておく
    env ANDROID_AVD_HOME=$HOME/.android/avd/gradle-managed
    emulator –avd {AVD名}
    p より正確に再現したいときは、以下のファイルを参考に
    emulatorコマンドのオプションを付ける
    (GMDでエミュレータを起動したときの環境変数や
    コマンドラインオプションなどが記録されている)
    app/build/outputs/androidTest-results/
    managedDevice/(省略)/emulator.1.ok.txt
    47

    View Slide

  48. (参考) emulator.1.ok.txtの例
    48
    EXECUTING: /usr/local/Caskroom/android-
    sdk/4333796/emulator/emulator @dev31_default_x86_64_Pixel_5 -
    no-window -no-audio -gpu auto-no-window -read-only -no-boot-
    anim -id :app:pixel5api31aospDebugAndroidTest
    CURRENT_WORKING_DIRECTORY: ...
    START_TIME: ...
    ENVIRONMENT: ...
    ANDROID_AVD_HOME=/Users/sumio.toyama/.android/avd/gradle-
    managed
    *****************************************
    STDOUT/STDERR BELOW

    View Slide

  49. エミュレータを起動した状態でテストを動かす②
    p Android Studioや
    ./gradlew connected{バリアント}AndroidTest
    などで通常通りテストを実⾏してデバッグする
    p テストが終了しても勝⼿にファイルが消えない
    p デバッグ実⾏も可能
    49

    View Slide

  50. その他のTips: テストの録画(テスト全体を1ファイルに録画)
    p JUnit4のRunListenerを使って、初回のテスト開始前に
    screenrecordコマンドを実⾏する
    p 標準出⼒をreadしなければコマンド終了を待たずに先に進める
    p 全テスト終了時(RunListener.testRunFinished())に
    実⾏中のscreenrecordコマンドをkillする
    p "pidof screenrecord" でpidを探す
    p 探したpidに対して"kill –INT $pid"
    p 録画したmp4はadditionalTestOutputDirで取り出す
    参考: JUnit Test Ruleとしての実装サンプル ScreenRecordRule.kt
    https://gist.github.com/mkeeda/30b8cfdcec53859a2cd39cac36d7fc9e
    50

    View Slide

  51. その他のTips: そのほか①
    p エミュレータの状態がおかしいので⼀度Cold Bootしたい
    p GMDが作成したAVDでエミュレータを起動する⽅法を使って、
    -no-snapshot-loadオプションを付けて起動・終了する
    p エミュレータをキッティングしておきたい
    (Googleアカウントログインなど)
    p ./gradlew {デバイス名}Setup で、GMDにAVDだけ作成させる
    p そのAVDでエミュレータを起動し、必要な操作を⾏って終了する
    51

    View Slide

  52. その他のTips: そのほか②
    p (デバイスグループなど)複数のAVDをまとめてテストする
    と結果が不安定になる問題を解決したい
    p GMDインスタンス数の並列度を下げる(AGP 7.4+)
    -Pandroid.experimental.testOptions.managedDevices
    .maxConcurrentDevices=1
    p Gradleタスクの並列度を下げる
    -Dorg.gradle.workers.max=1
    p 事前にpackageDebugAndroidTestで並列にビルドしておき、
    テストだけ本オプションを付けるのがおすすめ
    52

    View Slide

  53. これらの⼯夫でも対応できないこと
    p エミュレータ起動時のコマンドラインオプションを
    カスタマイズできない
    (とはいえconfig.iniでも指定できる項⽬が多い)
    p (エミュレータ起動中の)
    テスト開始直前・終了直後に処理を挟み込めない
    p JUnit4のRunListenerとexecuteShellCommandを使えば
    テスト開始直前・終了直後にshellコマンドの実⾏は可能
    53

    View Slide

  54. ここまでのまとめ
    p 以下の⼿段で、困りごとは概ね解決できる
    p --enable-displayオプション
    p config.iniのカスタマイズ
    p ANDROID_AVD_HOME環境変数を指定した
    エミュレータ起動
    p JUnit4のRunListenerで最初のテスト開始前にシェルコマンド発⾏
    p エミュレータ起動時のオプションを変更したり、
    テスト実⾏前後に任意の処理を挟み込むのは難しい
    54

    View Slide

  55. Agenda
    55
    1. GMD (Gradle Managed Devices)の使い⽅
    2. Androidエミュレータについておさらい
    3. GMDの困るところに対応する
    4. テストの種類別GMD活⽤シーン
    5. CIで動かすときのポイント
    6. まとめ

    View Slide

  56. テストの種類別GMD活⽤シーン
    1. Robolectricが必要なLocal Testの移⾏
    2. UIテスト
    3. スクリーンショットテスト
    56

    View Slide

  57. Robolectricが必要なLocal Testの移⾏①
    エミュレータ(GMD)で動かせばテスト忠実度は確実に上がる
    p Roblectricのバージョンアップ対応⼯数をゼロにできる
    p GMDへの移⾏は⽐較的容易なはず
    p src/test から src/androidTestへ移動
    (src/sharedTest はChipmunkから使えなくなった)
    p Robolectric固有のアノテーション(@Configなど)の削除
    p AVDのカスタマイズが必要なケースは少ないはず
    p 軽量なATD (Automated Test Device)でも動作するはず
    57

    View Slide

  58. Robolectricが必要なLocal Testの移⾏②
    p GMD (ATD)に移⾏した場合のテスト実⾏時間は?
    p 1テストクラス、18テストケースで計測
    p iMac Pro 2017 3.2GHz Xeon 8コア、32GB RAM
    58
    Robolectric GMD (ATD)
    テストクラス初回ロード 6〜15sec 0.6〜0.7sec
    エミュレータ起動 0sec 40〜60sec
    テスト実⾏時間
    (初回ロード以外)
    0.900〜1.000sec 0.200〜0.300sec

    View Slide

  59. Robolectricが必要なLocal Testの移⾏②
    p エミュレータの起動はとても遅い
    p 個々のテスト実⾏時間はエミュレータが3倍程度速い
    p 該当するテストが⼤量にあれば時間的にもペイするかも???
    p 忠実度とメンテナンス性を期待してGMDに移⾏するのは⼀案
    59
    Robolectric GMD (ATD)
    テストクラス初回ロード 6〜15sec 0.6〜0.7sec
    エミュレータ起動 0sec 40〜60sec
    テスト実⾏時間
    (初回ロード以外)
    0.900〜1.000sec 0.200〜0.300sec

    View Slide

  60. UIテスト
    p AVDのカスタマイズ無しに動くテストはGMDで
    p 環境差異による不安定なテストを減らせる
    p 軽量版でない⽅のGMDを使うのが無難
    p 軽量のATD (Automated Test Device)では画⾯表⽰不可
    p UIテストで使えるTips
    p 画⾯を⾒ながら動かす: --enable-displayオプション
    p ⾔語設定を英語以外にしたい: io.appium.settingsアプリ
    60

    View Slide

  61. スクリーンショットテスト
    p 判断基準やTipsはUIテストと同じ
    p 軽量版でない⽅のGMDが無難
    p ATDで使えるスクリーンショットはCanvasにView.draw()する⽅式のみ
    p スクリーンショット保存先に注意
    p /sdcard/Android/media/{アプリケーションID}/
    から始まるディレクトリに保存する
    p 保存したスクリーンショットはadditionalTestOutputDir
    オプションを使って取り出す
    61

    View Slide

  62. GMDが使えるシーンまとめ
    p Robolectricが必要なLocal Test
    p ⾼速化は期待できないが忠実度とメンテナンス性に期待
    p UIテストやスクリーンショットテスト
    p AVDのカスタマイズ無しに動くものなら利⽤できる
    ただし・・・
    CIでもGMDが動かないと効果半減なことに注意
    62

    View Slide

  63. Agenda
    63
    1. GMD (Gradle Managed Devices)の使い⽅
    2. Androidエミュレータについておさらい
    3. GMDの困るところに対応する
    4. テストの種類別GMD活⽤シーン
    5. CIで動かすときのポイント
    6. まとめ

    View Slide

  64. CI環境でGMDを使う前に意識したいこと
    既に⽤意されているStep・Actionなどは
    GMDよりカスタマイズできる項⽬が多い
    p カスタマイズが必要なら既存の⽅法にとどまった⽅が楽
    p Bitrise: AVD Manager Step・Wait for Android emulator Step
    https://devcenter.bitrise.io/en/steps-and-workflows/workflow-recipes-for-android-apps/-
    android--run-tests-using-the-emulator.html
    p CircleCI: Android Orbの android/start-emulator-and-run-tests Step
    https://circleci.com/docs/ja/android-machine-image
    p GitHub Actions: malinskiy/action-android/emulator-run-cmd
    https://github.com/Malinskiy/action-android
    p Jenkins: Android Emulator Plugin
    https://github.com/jenkinsci/android-emulator-plugin
    64

    View Slide

  65. ポイント1: エミュレータが動作するか確認する
    p 仮想環境ではNested Virtualizationが必要
    p CircleCIではマシンイメージを使う(Dockerイメージ不可)
    p エミュレータが動く潤沢なRAMが必要
    p Gradleの消費メモリも考えると8GBでは⾜りない
    p 既存のエミュレータ利⽤に関する設定例を参考にする
    p Bitrise: 情報なし(⼿許ではAndroid & Docker, on Ubuntu 20.04で動作)
    p CircleCI: androidマシンイメージ (Linux Large)
    p GitHub Actions: macOS-10.15
    65

    View Slide

  66. ポイント2: 必要に応じてGradleオプションを付ける
    p headless環境(画⾯を表⽰できない環境)のとき
    -Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect"
    p AVDのSetupタスクがタイムアウトするとき
    -Pandroid.experimental.testOptions.managedDevices.setupTimeoutMinutes
    でタイムアウト時間を増やす
    (Minutesは誤記。正しくは秒)
    66
    (参考) SunflowerアプリのGitHub Actions設定
    https://github.com/android/sunflower/pull/785

    View Slide

  67. ポイント3: テスト失敗時の解析をやりやすくする
    p ログファイルをArtifactsに保存しておく
    app/build/outputs/androidTest-results/**
    p テストを録画し、動画ファイルをArtifactsに保存しておく
    (「その他のTips: テストの録画」参照)
    p 実⾏時ログをより詳しくするGradleオプションを付ける
    p --info
    p -Pandroid.experimental.testOptions.managedDevices.emulator.showKernelLogging=true
    67
    (参考) SunflowerアプリのGitHub Actions設定 https://github.com/android/sunflower/pull/785

    View Slide

  68. GMDでAVDをカスタマイズしたいとき①
    ビルド間で実⾏環境を保持できるケースでは容易
    (⾃前で調達したJenkinsビルドマシンなど)
    1. 事前に{デバイス名}SetupタスクでAVD作成
    2. 作ったAVDでエミュレータを起動してキッティング
    3. エミュレータ終了でディスクイメージが保存される
    4. 以降、GMDのテストタスク実⾏でキッティングしたAVDが
    利⽤される
    68

    View Slide

  69. GMDでAVDをカスタマイズしたいとき②
    ビルド毎に実⾏環境が作り直されるサービスでは難しいが、、
    (CircleCI、Bitrise、GitHub ActionsのGitHub-hosted runnerなど)
    p AVDのconfig.iniの書き換えで済む範囲なら可能
    (ディスクサイズ、RAMサイズの増加など)
    1. {デバイス名}SetupタスクでAVDを作る
    2. (sedコマンドなどで)作られたAVD内のconfig.iniを書き換える
    3. GMDのテストタスクを実⾏する
    69

    View Slide

  70. GMDでAVDをカスタマイズしたいとき③
    p ディスクイメージのカスタマイズは⼒技が必要
    1. ⼿許のマシンで{デバイス名}SetupタスクでAVDを作る
    2. 作ったAVDでエミュレータ起動・キッティング(Apple Siliconは未確認)
    3. AVD内の以下のディスクイメージをGitHubリポジトリなどに保存
    (数GBになるので注意。LFS推奨)
    p userdata-qemu.img.qcow2
    p encryptionkey.img.qcow2
    p 状況によっては他のイメージファイルも必要かも知れない
    4. config.ini書き換えの要領でディスクイメージを差し替える
    70

    View Slide

  71. ここまでのまとめ
    p 本当にGMD使った⽅が良いか考える
    p AVDのカスタマイズが必要なら敢えてとどまる選択肢も
    p ポイントは3つ
    p エミュレータが起動できる環境を⽤意する
    p 必要に応じてGradleオプションを付ける
    p テスト失敗時の解析をやりやすくする
    p GMDでAVDをカスタマイズする場合は程々に・・
    71

    View Slide

  72. Agenda
    72
    1. GMD (Gradle Managed Devices)の使い⽅
    2. Androidエミュレータについておさらい
    3. GMDの困るところに対応する
    4. テストの種類別GMD活⽤シーン
    5. CIで動かすときのポイント
    6. まとめ

    View Slide

  73. p Gradle Managed Device (GMD) の設定⽅法、使い
    ⽅、⾜りない点を補う⽅法について説明しました
    p この内容でかなりのことが出来るようになるはずです
    p テストの種類別にGMDを使うと便利なケース、
    そうでないケースを説明しました
    p GMD活⽤の前提となる
    CIで動かすときのポイントもあわせて紹介しました
    73

    View Slide

  74. 参考URL①
    p 公式ドキュメント
    https://d.android.com/studio/test/gradle-managed-devices
    p Android Code Search (Gradleのオプションが定義されている場所)
    https://bit.ly/3rrFZp8 (cs.android.com)
    p Android Sunflower with Compose (GitHub Actions設定例)
    https://github.com/android/sunflower
    p Appiumのio.appium.settingsアプリ
    https://github.com/appium/io.appium.settings
    p GitHub Gist: mkeeda/ScreenRecordRule.kt
    https://gist.github.com/mkeeda/30b8cfdcec53859a2cd39cac36d7fc9e
    74

    View Slide

  75. 参考URL②
    p tkmnzm
    「Androidのテストで利⽤できるスクリーンショット取得APIのまとめ」
    https://qiita.com/tkmnzm/items/c25c43a8bac07bb90dfb
    p Bitrise「(Android) Run tests using the emulator」
    https://bit.ly/3Csu3K5 (devcenter.bitrise.io)
    p CircleCI「AndroidイメージのMachine Executorでの使⽤」
    https://circleci.com/docs/ja/android-machine-image
    p GitHub Actions: action-android
    https://github.com/Malinskiy/action-android
    p Android Emulator Plugin for Jenkins
    https://github.com/jenkinsci/android-emulator-plugin
    75

    View Slide

  76. この発表を参考に
    Gradle Managed Virtual Devicesを使った
    エミュレータ上でのテストを
    試してみてください
    ありがとうございました!
    76

    View Slide