Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

⾃⼰紹介 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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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作成 エミュレータ起動 テスト実⾏ アプリ消去 エミュレータ終了 テストレポート作成

Slide 7

Slide 7 text

(参考) バージョンの関係 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現在の、メジャーバージョンごとの最新版

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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 参照

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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の設定 ディスクイメージ

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

別アプリの助けを借りて⾔語設定を変更する ① 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した状態で インストールしてくれる

Slide 37

Slide 37 text

別アプリの助けを借りて⾔語設定を変更する ② 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 {地域}

Slide 38

Slide 38 text

別アプリの助けを借りて⾔語設定を変更する ② 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 {地域}

Slide 39

Slide 39 text

別アプリの助けを借りて⾔語設定を変更する ② 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 {地域}

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

テスト終了時にファイルを取り出す② 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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

エミュレータを起動した状態でテストを動かす① 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

Slide 48

Slide 48 text

(参考) 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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

その他の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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

ポイント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

Slide 66

Slide 66 text

ポイント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

Slide 67

Slide 67 text

ポイント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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

参考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

Slide 75

Slide 75 text

参考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

Slide 76

Slide 76 text

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