O slideshow foi denunciado.
Seu SlideShare está sendo baixado. ×

CEDEC2021 Android iOS 実機上での自動テストをより楽に有意義にする為に ~端末管理・イメージ転送・動画記録等の周辺情報のノウハウ共有~

Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio

Confira estes a seguir

1 de 188 Anúncio

CEDEC2021 Android iOS 実機上での自動テストをより楽に有意義にする為に ~端末管理・イメージ転送・動画記録等の周辺情報のノウハウ共有~

Baixar para ler offline

CEDEC 2021 の講演資料です。
ノートに講演で話した内容をそのまま記載ありますので、
講演内容を完全に把握したい方はダウンロードしての閲覧をお勧めします。

株式会社セガ 開発技術部 廣島岳史/竹原涼

CEDEC 2021 の講演資料です。
ノートに講演で話した内容をそのまま記載ありますので、
講演内容を完全に把握したい方はダウンロードしての閲覧をお勧めします。

株式会社セガ 開発技術部 廣島岳史/竹原涼

Anúncio
Anúncio

Mais Conteúdo rRelacionado

Diapositivos para si (20)

Semelhante a CEDEC2021 Android iOS 実機上での自動テストをより楽に有意義にする為に ~端末管理・イメージ転送・動画記録等の周辺情報のノウハウ共有~ (20)

Anúncio

Mais recentes (20)

CEDEC2021 Android iOS 実機上での自動テストをより楽に有意義にする為に ~端末管理・イメージ転送・動画記録等の周辺情報のノウハウ共有~

  1. 1. Android/iOS 実機上での自動テストを より楽に有意義にする為に ~端末管理・イメージ転送・動画記録等の周辺情報のノウハウ共有~
  2. 2. © SEGA 目次 - Android Android 準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
  3. 3. © SEGA 目次 -iOS 準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ iOS XCodeビルド アプリを転送・起動 ミラーリング映像の録画開始 テスト実行 ミラーリング映像の録画停止 アプリの終了 録画ファイルのリネーム
  4. 4. © SEGA ゲームコンテンツ&サービス事業本部 技術本部 開発技術部 廣島 岳史 自己紹介 SEGA入社後 アーケード向けのライブラリ開発やツール作成などに従事 最近ではプランナー・デザイナに向けたGitHubEnterprise用のツール の作成やUnity向け自動テスト支援ソリューションを開発しています
  5. 5. © SEGA • 本講演内容の撮影、SNS投稿は OK • 後日、CEDIL で資料を公開 • 講演中も質疑が可能です。 コメントに書き込んでください • 講演後にZoomによる質疑応答を実施 • 資料に記載されている会社名、システム名、製品名、サービス名は各社の登録商標または 商標です • Android ロボットは、Google が作成および提供している作品から複製または変更したもの であり、 クリエイティブ・コモンズ表示 3.0 ライセンスに記載された条件に従って使用しています
  6. 6. © SEGA • 自動テスト全体の流れ • テストとその周辺環境に関して • 具体的な環境構築の説明 • 運用時に発生した問題とその解決方法の共有 • 今後の展望 アジェンダ
  7. 7. © SEGA 自動テスト環境の構成
  8. 8. © SEGA 構築した自動テスト環境の構成図 USB テストフレームワーク 通信による操作 パラメータ送受信 テストの実行 ネットワーク
  9. 9. © SEGA 本講演で取り上げる部分
  10. 10. © SEGA 使用しているソフトウェア ミラーリング (Android) sndcpy サウンドのミラーリング用のソフトのみ ミラーリング (iOS) Quick Time Player ミラーリング (Android) scrcpy VLC RPA Automator 録画 OBS Studio
  11. 11. © SEGA ビルド&端末制御&録画担当(Mac) アプリケーションのビルド 端末へのアプリケーションのインストール 端末情報の収集 テスト画面の録画 iOSアプリのビルドを行う事からMacを採用 Macのバージョンは Big Sur : 11.4 使用しているMacは Intel CPU
  12. 12. © SEGA モバイル端末 (iOS / Android) 主な役割 アプリケーションの実行 テストフレームワークとの通信 ビルドマシンとはUSBを用いて接続 テストフレームワークとはWi-Fiで通信
  13. 13. © SEGA 全体の流れ(Android) Android 準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
  14. 14. © SEGA 全体の流れ(iOS) 準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ iOS XCodeビルド アプリを転送・起動 ミラーリング映像の録画開始 テスト実行 ミラーリング映像の録画停止 アプリの終了 録画ファイルのリネーム
  15. 15. © SEGA これらに関してはこの講演では共有しません • Android/iOS アプリのビルド • テストの実行 • テスト結果の解析や通知 共有しない項目
  16. 16. © SEGA 準備フェーズ USB 端末情報の 取得 ミラーリン グの準備 ビルド (Android) アプリケー ションを転送 (Android) 録画用ソフ トの起動 1 2 3 4 5
  17. 17. © SEGA テスト実行フェーズ(Android) USB アプリを起動 ミラーリン グした映像 の録画開始 テストの実 行 ミラーリン グした映像 の録画停止 アプリを終了 録画ファイ ルのリネー ム 1 2 3 4 5 6
  18. 18. © SEGA テスト実行フェーズ(iOS) USB XCodeビルド アプリを転 送・起動 ミラーリン グした映像 の録画開始 テスト実行 ミラーリン グした映像 の録画停止 アプリを終了 録画ファイル のリネーム 3 2 1 4 5 6 7
  19. 19. © SEGA 終了フェーズ USB 録画用ソフトの 終了 端末映像のミ ラーリング停止 テスト結果の解 析と通知処理 1 2 3
  20. 20. © SEGA  なぜ実機テストが必要か  テストフレームワークについて  オンプレ自前環境 vs クラウドサービス  自動テストと録画の関係 本題に入る前に
  21. 21. © SEGA • エミュレータ―を用いたテストだけでは不十分 • 端末でのみ発生する問題 なぜ実機でテストを行うのか
  22. 22. © SEGA  そもそも関数が無かった  ネイティブの関数の挙動が変わっていた 特定の端末・特定のバージョンで発生した 動かしてみるまで分からない 特定の端末で発生した不具合
  23. 23. © SEGA テストフレームワークについて
  24. 24. © SEGA • テストプロジェクトの作成 • テストスクリプトの作成 • テストスクリプトの実行 • テストレポートの出力 テストフレームワークの主な役割
  25. 25. © SEGA NUnit xunit MSTest.TestFramework Selenium Appium 代表的なテストフレームワーク ブラウザ .NET .NET .NET モバイル
  26. 26. © SEGA • テストフレームワークとアプリケーションが どのようにやり取りをするのかがポイント テストフレームワークと環境構築 テストコード
  27. 27. © SEGA • ゲームでは独自フレームワークの場合も多い 環境構築を視野に入れる事が重要 テストフレームワークを選定・実装する際 は、自動テスト環境の構築まで視野に入れて 選定を行う事をお勧めします
  28. 28. © SEGA 自動テスト環境の準備
  29. 29. © SEGA クラウドのテストサービス 近年端末の種類も豊富なクラウドのテストサービ スが多く登場  AWS Device Farmなどが有名  サービスを介して実機でテストを実行  端末を用意する必要が無い  端末の種類も豊富 テストコード
  30. 30. © SEGA • 以前はオンプレしか選択肢は無かった • プロジェクトの都合や予算で判断 オンプレミス vs クラウドサービス
  31. 31. © SEGA • 並列実行に強み • 端末を用意する必要が無い • 端末の種類が豊富 クラウドサービスの特徴(メリット)
  32. 32. © SEGA • お値段 • 使用可能なテストフレームワークに制限がかか る事もある • 他の人が端末を利用していて使えない事も クラウドサービスの特徴(デメリット)
  33. 33. © SEGA • お値段 • 自前のテストフレームワークの採用が可能 • テスト実行していない時は別の用途に転用可能 オンプレミス環境の特徴(メリット)
  34. 34. © SEGA • 端末を用意する必要がある • 構築・運用については全て自前 • 構築に関する知識が必要 当講演で解消可能! オンプレミス環境の特徴(デメリット)
  35. 35. © SEGA ハイブリッド(クラウド+オンプレミス) USB Azure pipelines self hosted agent ビルドからデプロイまでをクラウドで実行 テストをオンプレミスで実行 Azure Pipelines self –hosted agent を使う
  36. 36. © SEGA • お値段 • 独自形式のテストフレームワーク • 導入するプロジェクトの秘匿性が高くテスト環 境を外に出すリスクが取れなかった オンプレミスを採用しました
  37. 37. © SEGA テスト実行中の録画について
  38. 38. © SEGA • 再現性の低いバグの発生手順の確立 • 不具合の内容確認の容易性 実機テストでの録画の必要性  自動テストレポートにテスト動画を含める  BugTrackingSystemに動画付きで投稿する 効果的な使用例
  39. 39. © SEGA • ミラーリングしたものを録画 • 端末で録画 • HDMI分配器を利用する • カメラを用いて直接撮影する 録画手法について
  40. 40. © SEGA ミラーリング メリット • タイトル毎に録画機能を実装しな くて良い • 録画ファイルの取り扱いが簡単 デメリット • 複数端末同時録画が難しい ミラーリングソフト 録画を行うデバイス
  41. 41. © SEGA 端末で録画 メリット • 複数端末同時録画が可能 • 並列でテストが可能 デメリット • タイトル毎に録画機能の実装が必要 • 端末毎にデバッグ • 録画ファイルの取り扱いが複雑 画面を録画 録画データ転送
  42. 42. © SEGA HDMI分配器を利用する メリット • 環境構築が容易 • 録画機能を実装しなくて良い デメリット • 端末との相性問題 • 端末数分の分配器用意する必 要がある MHL変換アダプタ HDMI分配器 録画を行うデバイス
  43. 43. © SEGA カメラで録画 メリット • 環境構築が比較的容易 デメリット • 録画データの取り扱いが複雑 • 録画データのエンコーディン グを自分で行う必要がある • 複数端末分の機材が必要
  44. 44. © SEGA 採用理由 • タイトル毎に録画機能を実装しなくて良い • データの取り扱いが容易な点 • 複数端末での実行が可能な点 が決め手になりました ミラーリングを採用しました
  45. 45. © SEGA • Andoroidでの録画方法 – MediaProjection APIで録画 – REQUEST_MEDIA_PROJECTIONなどの権限 が必要 • iOSでの録画方法 – ReplayKit について 端末での録画を行う場合(補足)
  46. 46. © SEGA 前半まとめ テストフレームワーク 自動化を視野に選定・実装しましょう 自動化環境 クラウドサービスも多く存在します 録画 自動テストと録画は相性◎ 積極的に利用しましょう
  47. 47. © SEGA ゲームコンテンツ&サービス事業本部 技術本部 開発技術部 竹原 涼 自己紹介 【登壇歴】 CEDEC 2020 「技術同人作家になろう ~働き方改革時代におけるエン ジニアのレベルアップの一例~」 Unite Tokyo 2019 「大量のアセットも怖くない!~HTTP/2による高 速な通信の実装例~」 CEDEC 2018、CEDEC 2016、CEDEC 2015 プロダクション関連のラ ウンドテーブル GDC2016 報告会 「GDC16にみる自動化技術とテストのトレンド」
  48. 48. © SEGA 具体的な環境構築の流れ
  49. 49. © SEGA • 右上にプラットフォームを示すアイコンがあります 資料の見方 Android iOS
  50. 50. © SEGA 準備フェーズ 準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
  51. 51. © SEGA 端末情報の 取得 ミラーリン グの準備 ビルド (Android) アプリケー ションを転送 (Android) 録画用ソフ トの起動 端末情報の取得 USB 1 2 3 4 5
  52. 52. © SEGA • 実機へのアプリ転送・実行には端末情報が必要 • Android  デバイス名/デバイスID • iOS  デバイス名/UUID • IPアドレスも必要な場合はここで取得しておくと楽 端末情報の取得
  53. 53. © SEGA • adbコマンド結果をパースすることにより取得 • デバイス名/ID  adb devices –l • IPアドレス  adb -s “デバイスID” shell ip addr show 端末情報の取得 Android
  54. 54. © SEGA Extended Choice Parameter Plugin を利用してビルドパラメータで 端末IDを選択可能に def p = "adb devices -l".execute() p.waitFor() def idList = [] def deviceNameList = [] def lines = p.inputStream.readLines() lines.each { def matcher = (it =~ /([0-9a-zA-Z]+) (.+)model:(.+) device:/) while (matcher.find()) { idList.add(matcher.group(1)) deviceNameList.add(matcher.group(3)) } } return deviceNameList 端末情報の取得 - Jenkins例 Android
  55. 55. © SEGA 選択されたデバイスIDからIPアドレスを取得する def id = ““ // id には先ほど選択された値を入れる def ip = ”“ def ipaddr = String.format(“adb -s %s shell ip addr show”, id).execute() ipaddr.waitFor() def ipLines = ipaddr.inputStream.readLines() ipLines.each { def ipMatcher = (it =~ /inet ([0-9.]+)/([0-9]+) brd/) while (ipMatcher.find()) { ip = ipMatcher.group(1) } } // ここでipをファイルに書き込むなり何なりして下流に受け渡す 端末情報の取得 - Jenkins例 Android VPNを張っている場合はVPNソフトに合わせた条件に 変えてあげる必要有り 例 def ipMatcher = (it =~ /inet ([0-9.]+)/([0-9]+) scope global tun0/)
  56. 56. © SEGA • xcrunコマンド結果をパースすることにより取得 • デバイス名/UUID  xcrun instruments –s • IPアドレス  Bonjourの利用がお勧め 端末情報の取得 iOS
  57. 57. © SEGA • 対応端末にデバイス名指定でアクセスできる • デバイス名に.localを付けてアクセス  デバイス名は準備フェーズで取得したものを流用 Bonjour iOS
  58. 58. © SEGA • 以下のいずれかで実現  自前でBonjourを実装しIPアドレス取得  Bonjour対応アプリをMacOS上で起動しておく Bonjourを使ったアクセス iOS
  59. 59. © SEGA • 同一LAN内限定 • ActiveDirectoryと併用する場合に注意  ローカルドメイン名に.localは使わない Bonjour注意事項 iOS
  60. 60. © SEGA • パケットキャプチャをすることで対応可能  特殊な事例且つ長くなるので詳細はAppendixで  Unityの場合の具体例が掲載されています 非同一LAN環境への対応 iOS
  61. 61. © SEGA Android同様Extended Choice Parameterでビルドパラメータ化 def devices = “xcrun instruments -s”.execute() devices.waitFor() def deviceNameList = [] def lines = devices.inputStream.readLines() lines.each { def matcher = (it =~ /([^ ]+) (([0-9.]+)) [([-A-Za-z0-9]+)]$/) while (matcher.find()) { deviceNameList.add(matcher.group(1)) } } return deviceNameList 端末情報の取得 - Jenkins例 iOS
  62. 62. © SEGA ミラーリングの準備 端末情報の 取得 ミラーリン グの準備 ビルド (Android) アプリケー ションを転送 (Android) 録画用ソフ トの起動 USB 1 2 3 4 5
  63. 63. © SEGA • 公式のミラーリングソフトは存在しない  OSS やフリーのツールを利用するのが一般的 • 検証を行ったもの  〇 scrcpy 採用!  △ ApowerMirror  ✖ Androidtool-mac, Vysor, Mobizen ソフトウェアの選定 Android
  64. 64. © SEGA • shell から操作可能 • オプションが豊富 • 端末にアプリケーションのインストールが不要 • USB経由でミラーリング可能 • ミラーリングされた画面からタッチ操作可能 scrcpyの特徴 Android
  65. 65. © SEGA • 音声ミラーリング機能はない • 録画機能は可能だが無圧縮 • コマンドで起動後、処理が返ってこない scrcpy注意事項 Android
  66. 66. © SEGA • 以下の3通りのいずれかで対応可能 1. ProcessTreeKillerから逃れる (お勧め!) 2. Pipelineで並列化する 3. AppleScriptを使ってJenkinsから切り離す scrcpyをJenkinsで使う場合 Android
  67. 67. © SEGA • Jenkinsはジョブ中に起動したプロセスをその ジョブ終了時に強制終了する  https://wiki.jenkins.io/display/JENKINS/ProcessTreeKiller • nohup & を使ってもジョブを抜ける際にアウト ProcessTreeKiller補足 Android
  68. 68. © SEGA • shellの場合は環境変数 BUILD_ID に dontKillMe プロセスパス(名) を入れて回避 • shell設定例  export BUILD_ID=dontKillMe scrcpy nohup scrcpy <options> & ProcessTreeKiller補足 Android
  69. 69. © SEGA • PipelineはJENKINS_NODE_COOKIEに設定 • Pipeline実行例  steps { sh ''' export JENKINS_NODE_COOKIE=dontkillMe nohup scrcpy <options> & ''' } ProcessTreeKiller補足 Android
  70. 70. © SEGA • sndcpyを使う  scrcpyと一緒に使う為に作成されたOSS 音声ミラーリングしたい Android
  71. 71. © SEGA • Android 10から使用可能  内部的にAudioPlaybackCapture APIを使用 • 端末へのアプリケーションインストールが必要 sndcpy注意事項 Android
  72. 72. © SEGA sndcpyというスクリプト内で以下が実行される 1. sndcpyを端末へインストール 2. 端末上でsndcpy起動 3. 端末側でポップアップが出る 4. ポップアップを閉じる (手動で「今すぐ開始」を押す) 5. PC側でVLCを起動する 音声ミラーリングまでの流れ Android ここを自動化したい
  73. 73. © SEGA • ポップアップはAndroid側が出しているので抑制 できない • 最終手段のAutomatorを利用  MacOSに標準搭載されているというRPAツール sndcpyカスタマイズ Android
  74. 74. © SEGA • ユーザ操作を記録・再現するRPAツール  アプリケーションとして保存できる  内部的にはAppleScript(後述)に落とし込まれる • レイアウトの変更には弱い  なるべく座標指定しないような実装にはなっている Automator Android
  75. 75. © SEGA • Apple 独自のスクリプト言語 • shellから呼び出し可能  shellの先頭に #!/usr/bin/env osascript を付ける • キーボードやマウス等の操作が可能 AppleScript Android
  76. 76. © SEGA • 資料が少ない  オンラインの公式ドキュメントは情報が古いことも • AppleScriptメニュー内にある用語説明がお勧め AppleScript注意事項 Android
  77. 77. © SEGA • 画面ロック中は操作できないものがある  キーボード、マウス操作 AppleScript注意事項 Android
  78. 78. © SEGA • 簡単な操作ならAppleScript単体で実装する • 複雑な操作はAutomatorで実装する  AppleScriptに変換して細部を修正可能 Automator運用方針 Android
  79. 79. © SEGA ポップアップクローズの自動化 Android
  80. 80. © SEGA Automatorで記憶された操作 Android
  81. 81. © SEGA Automatorの修正 Android ドラッグ&ドロップ 項目の内容がコピーされる
  82. 82. © SEGA Automatorの修正 Android ドラッグ&ドロップ コピーなので保存してもこの中の項目には反映されない これは1個目のコピー(編集はコピーしかできない) これは2個目のコピー
  83. 83. © SEGA Automatorの修正 Android イベントをここから全部消せる
  84. 84. © SEGA Automatorの修正 Android
  85. 85. © SEGA • ポップアップを閉じたことを確認してから次の 処理に進みたい  openコマンドでは終了を待てない • Automatorアプリ終了を待つAppleScriptを作成 Automatorアプリの終了を待つ Android
  86. 86. © SEGA doandwait_process.sh #!/usr/bin/env osascript on run {do_command, process_name} tell application "Terminal" do script do_command in currentTab delay 0.5 tell application "System Events" repeat if not (exists process process_name) then exit repeat end if delay 0.5 end repeat end tell end tell end run Automatorアプリの終了を待つ Android 引数で受け取ったコマンドを実行 起動したプロセスが存在する限り待つ
  87. 87. © SEGA 1. sndcpyを端末へインストール 2. sndcpy起動 3. 端末側でポップアップが出る 4. ポップアップを閉じる 5. PC側でVLCを起動する 音声ミラーリングまでの流れ Android sndcpyを分割して自前のAutomatorの処理を挟む strat_vlc.sh sndcpy Automator処理
  88. 88. © SEGA #!/bin/bash set –e ADB=${ADB:-adb} SNDCPY_APK=${SNDCPY_APK:-sndcpy.apk} SNDCPY_PORT=${SNDCPY_PORT:-28200} serial= if [[ $# -ge 1 ]] then serial="-s $1“ echo "Waiting for device $1...“ else echo 'Waiting for device...‘ fi "$ADB" $serial wait-for-device "$ADB" $serial install -t -r -g "$SNDCPY_APK" || { echo 'Uninstalling existing version first...‘ "$ADB" $serial uninstall com.rom1v.sndcpy "$ADB" $serial install -t -g "$SNDCPY_APK“ } "$ADB" $serial forward tcp:$SNDCPY_PORT localabstract:sndcpy "$ADB" $serial shell am start com.rom1v.sndcpy/.MainActivity sndcpy分割 (sndcpy) Android
  89. 89. © SEGA #!/bin/bash set –e export VLC=/Applications/VLC.app/Contents/MacOS/VLC VLC=${VLC:-vlc} SNDCPY_PORT=${SNDCPY_PORT:-28200} "$VLC" -Idummy --demux rawaud --network-caching=50 --play-and-exit tcp://localhost:"$SNDCPY_PORT" sndcpy分割 (start_vlc) Android
  90. 90. © SEGA export BUILD_ID=dontKillMe scrcpy nohup scrcpy –b 30M –window-title ‘Title’ –turn-screen-off –serial $ANDROID_ID & scrcpy - Jenkins例 Android オプションの意味は以下の通り • 端末のモニタの電源を切って起動 • ビットレートは30Mbps • ウィンドウのタイトルを「Title」にする  後述する録画の際に必要になってくるので必ず付ける • ANDROID_IDで指定したIDの端末をミラーリング
  91. 91. © SEGA # sndcpyインストールと起動 ./sndcpy # ポップアップの抑制 ./doandwait_process.sh "exec open -a SupSndcpyPopup" "SupSndcpyPopup" # VLCの起動 export BUILD_ID=dontKillMe start_vlc nohup ./start_vlc & sndcpy - Jenkins例 Android
  92. 92. © SEGA • scrcpy/sndcpyはWindowsにも対応  sndcpy.batを使う等細かい差異はあるが基本同じ対 応で自動化可能 • ポップアップの抑制にはWindows対応のRPA ツールで代用を Windowsでミラーリング Android
  93. 93. © SEGA • Quick Time Playerでミラーリングが可能  MacOSに標準インストール • Quick Time Player以外の候補は見つからず • 自動化についてはハマり所がいくつかある ソフトウェアの選定 iOS
  94. 94. © SEGA • Quick Time Playerで録画することは可能  ただしエンコーディング無し Quick Time Playerでの録画 iOS
  95. 95. © SEGA • ミラーリング映像から操作が可能 • shell経由での細かい実行をサポートしていない • 最終的に再びAutomatorに頼ることに Quick Time Playerの自動化 iOS
  96. 96. © SEGA Automatorでの起動 iOS
  97. 97. © SEGA export BUILD_ID=dontKillMe start_iphone_mirroring nohup open -a start_iphone_mirroring & Quick Time Player – Jenkins例 iOS
  98. 98. © SEGA • 複数のiPhoneが接続されている場合、Android 同様に端末を指定したい 複数デバイス対応 iOS
  99. 99. © SEGA • Automatorアプリは起動時引数に制限がある  ファイルパスしか渡せない • 環境変数にデバイス名を保存しておき、それを Automator内のAppleScriptで読み込む 複数デバイス対応 - Automator iOS
  100. 100. © SEGA AppleScriptを実行(devtech-iphoneを選択)の書き換え 元の実装 set uiScript to “click menu item ”devtech-iphone“ of menu 1 of UI Element 5 of window 1 of application process ”QuickTime Player““ 修正後の実装 set deviceName to system attribute "DeviceName“ set uiScript to "click menu item "" & deviceName & "" of menu 1 of UI Element 5 of window 1 of application process "QuickTime Player"" 複数デバイス対応 -AppleScript iOS デバイス名が埋まっているのでここを動的に差し替える • 呼び出し元で環境変数DeviceNameにデバイス名をexportしておく • 環境変数はAppleScriptからは to system attribute で読める
  101. 101. © SEGA 複数デバイス対応- Jenkins例 iOS export BUILD_ID=dontKillMe start_iphone_mirroring export DeviceName=“devtech-iphone“ nohup open -a start_iphone_mirroring & Jenkins側は環境変数設定を挟むだけでOK “あいふぉん”のような日本語はアウトなので注意
  102. 102. © SEGA 録画用ソフトの起動 端末情報の 取得 ミラーリン グの準備 ビルド (Android) アプリケー ションを転送 (Android) 録画用ソフ トの起動 USB 1 2 3 4 5 Android
  103. 103. © SEGA テスト実行フェーズ Android 端末情報の取得 ミラーリングの準備 Androidビルド アプリを転送 録画用ソフトの起動 アプリを起動 ミラーリング映像の録画開始 テストの実行 ミラーリング映像の録画停止 アプリを終了 録画ファイルのリネーム 準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ ビルド・転送は準備フェーズに実行 起動のみテスト毎に実行することで効率アップ
  104. 104. © SEGA • adb.exeを使用する  adb -s “デバイスID” install ”アプリケーションイメージのパス” アプリの転送 Android
  105. 105. © SEGA adb -s $ANDROID_ID install $APPLICATION_PATH アプリの転送 – Jenkins例 Android
  106. 106. © SEGA 録画用ソフトの起動 端末情報の 取得 ミラーリン グの準備 ビルド (Android) アプリケー ションを転送 (Android) 録画用ソフ トの起動 USB 1 2 3 4 5
  107. 107. © SEGA • 検証を行ったもの  〇 OBS Studio 採用!  △ scrcpy/Quick Time Player ソフトウェアの選定 Android iOS
  108. 108. © SEGA • シェルから起動オプションが指定可能 • ほぼ全ての操作のキーボードショートカット有 • websocketによる操作も可能 • 録画と同時にエンコーディング可能 • 配信でよく利用されており更新が非常に活発 OBS Studioの特徴 Android iOS
  109. 109. © SEGA • OBSはプロファイル単位で種々の設定が可能  起動時の引数でこのプロファイルを指定できる • 自動化用にプロファイルを作成しておく  プロファイル名にIDやデバイス名を使うと楽 事前設定 - プロファイル Android iOS
  110. 110. © SEGA • プロファイル毎に設定可能 • 複数の端末でテストを行う場合  プロファイルを端末毎に作成  端末数が多い場合にプロファイルの作成が手間  全ての解像度を包含できるような解像度で作成  余白ができてしまい見栄えが悪い(がテスト用途なので気にしない) 事前設定 – キャンバス Android iOS
  111. 111. © SEGA • 録画対象のウィンドウの設定が必要 • 名前で指定する  iOSはQuickTimePlayerのウィンドウ名をそのまま  Androidはscrcpyのオプションで指定 事前設定 – シーン Android iOS
  112. 112. © SEGA • シェル経由で終了することができない • 録画中にkillすると映像ファイルが壊れる • 「録画開始」、「録画終了」のキーボード ショートカットを設定し操作 事前設定 – ショートカット Android iOS
  113. 113. © SEGA • SoundFlowerというツールが必要 • OSとOBS両方でSoundFlowerの設定を行う 事前設定 – 録音 Android iOS
  114. 114. © SEGA • --startrecording で起動後自動で録画開始する • --profile “name” でプロファイル指定可能 • その他のパラメータは公式ドキュメント参照  https://github.com/obsproject/obs-studio/wiki/Launch-Parameters OBSの起動時引数 Android iOS
  115. 115. © SEGA export BUILD_ID=dontKillMe obs nohup open -a obs --args --profile $PROFILE_NAME & OBS – Jenkins例 Android iOS • 起動後自動で録画開始したい場合は --startrecording を入れる • 構築した環境ではテスト毎にOBS起動するコストが無駄なので起動と録 画開始は切り離している為にここでは –startrecording は入れていない
  116. 116. © SEGA • OBSもWindowsに対応 • キーストロークを行うアプリでショートカット を操作する Windowsで録画 Android
  117. 117. © SEGA • ロック中やRDPで運用しているPCでの録画は一 工夫必要  Macはロック中でも録画可能 • 資料末尾にAppendixとして記載 Windowsで録画
  118. 118. © SEGA テスト実行フェーズ Android 端末情報の取得 ミラーリングの準備 Androidビルド アプリを転送 録画用ソフトの起動 アプリを起動 ミラーリング映像の録画開始 テストの実行 ミラーリング映像の録画停止 アプリを終了 録画ファイルのリネーム 録画用ソフトの終了 ミラーリングの停止 結果の解析と通知処理 準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
  119. 119. © SEGA アプリケーションを転送・起動 USB アプリケー ションを起動 ミラーリング した映像の録 画開始 テストの実行 ミラーリング した映像の録 画停止 録画ファイル のリネーム 1 2 3 4 5 Android
  120. 120. © SEGA • 転送同様にadb.exeを使用する  adb -s “デバイスID” shell am start “パッケージ名/アクティビティ名” アプリの起動 Android
  121. 121. © SEGA adb -s $ANDROID_ID shell am start "$PACKAGE_NAME/$ACTIVITY_NAME" アプリの起動 – Jenkins例 Android
  122. 122. © SEGA 全体の流れ(iOS) iOS 端末情報の取得 ミラーリングの準備 録画用ソフトの起動 録画用ソフトの終了 ミラーリングの停止 結果の解析と通知処理 準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ XCodeビルド アプリを転送・起動 ミラーリング映像の録画開始 テスト実行 ミラーリング映像の録画停止 アプリの終了 録画ファイルのリネーム
  123. 123. © SEGA USB XCodeビルド アプリを転 送・起動 ミラーリン グした映像 の録画開始 テスト実行 ミラーリン グした映像 の録画停止 アプリを終了 録画ファイル のリネーム 3 2 1 4 5 6 7 アプリケーションを転送・起動
  124. 124. © SEGA • 転送/起動にはxcodebuildを用いる • xcodebuildでビルドと転送/起動を分ける  build-for-testing : ビルドのみ実行  test-without-building : 転送/起動を実行 アプリの転送/起動 iOS
  125. 125. © SEGA • 連続実行すると失敗する  端末側の状態がリセットされない  フルビルドで解消 test-without-building注意事項 iOS
  126. 126. © SEGA アプリのビルド/転送/起動 端末情報の取得 ミラーリングの準備 録画用ソフトの起動 録画用ソフトの終了 ミラーリングの停止 結果の解析と通知処理 準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ XCodeビルド アプリを転送・起動 ミラーリング映像の録画開始 テスト実行 ミラーリング映像の録画停止 アプリの終了 録画ファイルのリネーム 毎回フルビルドしたくない!! iOS
  127. 127. © SEGA • XCodeのキャッシュ内に生成された.appを削除 してbuild-for-testingすることで回避  .appの再生成だけなのでビルド時間は短い test-without-building連続実行 iOS
  128. 128. © SEGA • キャッシュされた.appのパス  /Library/Developer/Xcode/DerivedData/"xcodeproj名"-"ハッシュ値" /Build/Products/Debug-iphoneos/"プロダクト名".app • ハッシュ値の動的取得方法は不明  一度決まると変わることはないので、環境構築時に一 度手動でビルドして確認 test-without-building連続実行 iOS
  129. 129. © SEGA • Xcodeのテストであるxctestが必要 • 何もせずに永久に待機し続けるxctestを実行する ことにより疑似的にアプリの起動を再現する test-without-buildingを使うには iOS
  130. 130. © SEGA cd "Xcodeプロジェクト配置パス" # .appを削除 rm -rf /Library/Developer/Xcode/DerivedData/$XCODE_PROJ_NAME- $XCODE_DERIVED_HASH/Build/Products/Debug-iphoneos/$PRODUCT_NAME.app # xcodebuildでアプリケーションビルドのみ実行 xcodebuild build-for-testing "platform=iOS,id=$IPHONE_UUID" -scheme "実行したいXcodeのScheme名" ARCHS=$ARCH_TYPE アプリのビルド – Jenkins例 iOS
  131. 131. © SEGA cd “Xcodeプロジェクト配置パス” # xcodebuildでアプリケーションを転送/起動する xcodebuild test-without-building -destination “platform=iOS,id=$IPHONE_UUID” -scheme “実行したいXcodeのScheme名" ARCHS=$ARCH_TYPE アプリの転送/起動 – Jenkins例 iOS
  132. 132. © SEGA • 現在βのXcode13に追加される以下のオプション で再ビルド不要になりそう(未検証)  -test-itreations <number>  -retry-tests-on-failure  -run-tests-until-failure 補足① - test-without-building iOS
  133. 133. © SEGA • Xcode(GUI)からキーボードショートカット経由 で転送/起動する手もある  Automator(AppleScript)から操作 • RPAツールの利用はあくまで最終手段  他の解決方法がある場合はそちらの採用がお勧め 補足② - Xcodeをキーボード操作 iOS
  134. 134. © SEGA USB アプリを起動 ミラーリン グした映像 の録画開始 テストの実 行 ミラーリン グした映像 の録画停止 アプリを終了 録画ファイ ルのリネー ム 1 2 3 4 5 6 録画開始 Android
  135. 135. © SEGA USB XCodeビルド アプリを転 送・起動 ミラーリン グした映像 の録画開始 テスト実行 ミラーリン グした映像 の録画停止 アプリを終了 録画ファイル のリネーム 3 2 1 4 5 6 7 録画開始 iOS
  136. 136. © SEGA • OBSの事前設定で決めたキーボードショート カットを使用する • 呼び出しはAppleScriptを用いる 録画開始 Android iOS
  137. 137. © SEGA ショートカットに設定したキーを押下する #!/usr/bin/env osascript tell application "OBS“ activate tell application "System Events“ keystroke "s" using {command down, option down} end tell end tell 録画開始(AppleScript) Android iOS
  138. 138. © SEGA USB アプリを起動 ミラーリン グした映像 の録画開始 テストの実 行 ミラーリン グした映像 の録画停止 アプリを終了 録画ファイ ルのリネー ム 1 2 3 4 5 6 テストの実行 Android iOS
  139. 139. © SEGA • テストフレームワーク次第ではこのタイミング で実行開始が必要 テストの実行 Android iOS 通信による操作 パラメータ送受信 テストの実行
  140. 140. © SEGA • 例:今回構築した環境 テストの実行(例) Android iOS Jsonでテストしたい動作を指定 • テストケースに沿って操作を送信 • 返信結果からテストの成否を判定 Jsonを解析して侵入型の テストを実行 指定した動作の結果を返信
  141. 141. © SEGA • アプリの起動タイミングに仕込む  実行時の引数  adbは引数オプション有り  xcodebuildはプリプロセッサマクロを活用  テスト用コンフィグファイル  アプリ起動前に毎回端末に転送し直す等 テストの実行(非通信型) Android iOS
  142. 142. © SEGA 録画停止 Android iOS USB アプリを起動 ミラーリン グした映像 の録画開始 テストの実 行 ミラーリン グした映像 の録画停止 アプリを終了 録画ファイ ルのリネー ム 1 2 3 4 5 6
  143. 143. © SEGA • 録画開始同様キーボードショートカットを使用 #!/usr/bin/env osascript tell application "OBS“ activate tell application "System Events“ keystroke “q" using {command down, option down} end tell end tell 録画終了 Android iOS
  144. 144. © SEGA USB アプリを起動 ミラーリン グした映像 の録画開始 テストの実 行 ミラーリン グした映像 の録画停止 アプリを終了 録画ファイ ルのリネー ム 1 2 3 4 5 6 アプリの終了 Android iOS
  145. 145. © SEGA • adb.exeで終了させる  adb -s “デバイスID” shell am force-stop “パッケージ名” アプリの終了 Android
  146. 146. © SEGA adb -s $ANDROID_ID shell am force-stop $PACKAGE_NAME アプリの終了 – Jenkins例 Android
  147. 147. © SEGA • xcodebuildをpkillする  pkill “xcodebuild" アプリの終了 iOS
  148. 148. © SEGA USB アプリを起動 ミラーリン グした映像 の録画開始 テストの実 行 ミラーリン グした映像 の録画停止 アプリを終了 録画ファイ ルのリネー ム 1 2 3 4 5 6 録画停止 Android iOS
  149. 149. © SEGA • OBSのファイル名書式は日時等柔軟に指定可能 • しかし、起動時引数のようなものでテスト名を 動的に付与することはできない 録画ファイルのリネーム Android iOS
  150. 150. © SEGA • テスト終了毎にファイルをテスト名を付与した ものにリネームしてあげると結果確認時に分か り易い • shell例(移動するついでにリネーム)  mv -f $OBS_OUTPUT_PATH/*.mp4 $STORAGE_PATH/$TEST_NAME_`date "+%Y%m%d%H%M"`.mp4 録画ファイルのリネーム Android iOS ※CatchExceptionTest_202104021241.mp4のような名前で保存される
  151. 151. © SEGA 具体的な環境構築の流れ 端末情報の取得 ミラーリングの準備 Androidビルド アプリを転送 録画用ソフトの起動 アプリを起動 ミラーリング映像の録画開始 テストの実行 ミラーリング映像の録画停止 アプリを終了 録画ファイルのリネーム 録画用ソフトの終了 ミラーリングの停止 結果の解析と通知処理 準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
  152. 152. © SEGA 録画用ソフトの終了 USB 録画用ソフトの 終了 端末映像のミ ラーリング停止 テスト結果の解 析と通知処理 1 2 3 Android iOS
  153. 153. © SEGA • pkillすればOK  pkill "obs" OBSの終了 Android iOS
  154. 154. © SEGA ミラーリング停止 USB 録画用ソフトの 終了 端末映像のミ ラーリング停止 テスト結果の解 析と通知処理 1 2 3 Android iOS
  155. 155. © SEGA • scrcpyはOBS同様pkillすればOK  pkill "scrcpy“ • sndcpyはアンインストールする  adb uninstall com.rom1v.sndcpy scrcpy/sndcpyの終了 Android
  156. 156. © SEGA • 他のプロセス同様にpkillでOK  pkill "QuickTime Player" Quick Time Playerの終了 iOS
  157. 157. © SEGA 運用時に発生した問題とその解決方法の共有
  158. 158. © SEGA • Android/iOS共にOSの自動アップデート通知が テスト中に割り込みで入る  操作不能になりテストが失敗する原因に • どちらのOSも自動アップデートは抑止できるの で設定を忘れずにしておく OSアップデート通知問題
  159. 159. © SEGA • Automatorで記録したままの設定だとウェイト 値が不適切で動作が安定しないことがある  Automator運用方針項で述べたように、複雑な操作 をAutomatorで実装する場合はAppleScriptで細かい 調整を行おう Automator操作が時々失敗する
  160. 160. © SEGA • 録画映像に妙な余白が…… ノッチ対応アプリ録画映像の余白 ここ
  161. 161. © SEGA • ノッチ対応している為にできた余白だった  逆説的に余白はノッチ対応の証拠なので確認に使える ノッチ対応アプリ録画映像の余白
  162. 162. © SEGA ポップアップクローズ失敗 Android
  163. 163. © SEGA 今後の展望
  164. 164. © SEGA • 複数端末を並列でテストしたい  録画をどうするかが課題  OBSのキャンバスをうまく活用すれば……? • テスト中のパフォーマンスを取得したい  ミラーリングの負荷の影響がどうしても出る 展望
  165. 165. © SEGA 良い実機テストライフを!!
  166. 166. © SEGA Appendix
  167. 167. © SEGA Appendix Windowsで録画(ロック時の注意)
  168. 168. © SEGA • 以下の実装ではロック画面そのものを録画して しまう  Desktop Duplication API  (最新の)WinRTのWindows.Graphics.Capture ロック時に録画できないケース
  169. 169. © SEGA • アプリケーションの描画した結果画像を直接取 得する方法であれば録画可能  例:DXGIのPresentにフックを仕掛ける 自力で録画機能を実装する案
  170. 170. © SEGA • OBSの録画も前者の録画できない方式に該当 • そこで、RDP等でロック解除して自動処理を実 行する必要がある • しかしRDP接続に関しても録画は注意しないと いけない点がある OBSの場合
  171. 171. © SEGA Appendix Windowsで録画(RDP接続時の注意)
  172. 172. © SEGA • RDPで接続した状態であれば、ロック中でも録画 が可能  しかし常時RDP接続しておくわけにはいかない • テスト実行時にRDPが繋がっていなければ自動 的に接続を行う処理を挟む OBSとRDP接続を組み合わせて録画
  173. 173. © SEGA • 例えば、DockerでUbuntuを動作させ、その中 でRemminaというOSSでRDP接続を行えるよう な環境を構築する • テスト開始時に録画を行いたいPCのセッション の有無を確認し、存在していない場合は前述し たUbuntuからRemmina経由でRDPにて接続を 行う テスト実行時にRDP接続
  174. 174. © SEGA • RemminaによるRDP接続処理はUbuntuを Jenkinsのagentとして登録することにより実現 可能 • Ubuntu環境からRDP接続しているので画面ロッ クをしなくてもセキュリティが担保できる  物理画面はログイン画面が表示される • PC再起動を考慮してUbuntuの起動やログイン処 理も自動化しておくのがお勧め 補足
  175. 175. © SEGA set CURRENT_SESSION_ID=-1 for /f "tokens=3-4" %%a in ('query session %username%') do @if "%%b"=="Active" set CURRENT_SESSION_ID=%%a echo %CURRENT_SESSION_ID% exit /b %CURRENT_SESSION_ID% セッションの確認実装例
  176. 176. © SEGA • RDP切断時にtsconを用いてアクティブなセッ ションを切り替える方法も有り  tscon <現在のセッションID> /dest:console • tsconを忘れると録画が失敗してしまうので運用 には注意が必要 自動RDP接続対応が面倒な場合
  177. 177. © SEGA Appendix iOSのIPアドレス取得(非同一LAN環境)
  178. 178. © SEGA • パケットキャプチャ結果からIPアドレスをパー スする • rvictlを使ってMacOSから端末に仮想インター フェースをマウントし、これをtcpdumpするこ とでパケットキャプチャ可能  MacとiOS端末が非同一LAN内でも取得可能! パケットキャプチャ iOS
  179. 179. © SEGA • 仮想インターフェースを作成するアプリを立ち 上げると rvictl が切断させることがある  例 : Quick Time Playerでミラーリングを行う • tcpdumpはsudoが必要 • 端末側からMacOSへ何らかのパケットを送信す る必要がある パケットキャプチャ注意事項 iOS
  180. 180. © SEGA • 自作以外のアプリはshellから起動が難しい  xcodebuild経由でないといけない  QuickTimePlayerでミラーリングした画面をAutomator で操作してアプリ起動する方法は前述の切断問題がある為 にNG • 自前で以下の対応をするしかない  専用のアプリを作成する  テストを行うアプリに仕込みを入れる 端末から通信を行う iOS
  181. 181. © SEGA • UnityはDevelopmentフラグが有効の場合に ポート54997でデバッグ情報をマルチキャスト で投げる  https://docs.unity3d.com/Manual/TroubleShootingIPhone.html • マルチキャストでフィルタするとrvictlが出して いるパケットまでキャッチしてしまうので注意 端末から通信を行う – Unityの例 iOS
  182. 182. © SEGA • 投げられるパケット情報 端末から通信を行う – Unityの例 iOS IPが埋まっているので パースして活用
  183. 183. © SEGA rvictlを使って仮想インターフェースを作成(Pipeline) def rviStart = "rvictl -s ${params.IPHONE_UUID}".execute() rviStart.waitFor() def rviLines = rviStart.inputStream.readLines() def viName = "“ rviLines.each { def matcher = (it =~ /interface ([0-9a-zA-Z]+)/) while (matcher.find()) { viName = matcher.group(1) } } Jenkins - Unity例 iOS
  184. 184. © SEGA ポート54997のパケットからIPを抽出(Pipeline) def dump = "sudo tcpdump -i ${viName} -t -c 1 dst port 54997".execute() dump.waitFor() def lines = dump.inputStream.readLines() def ip = "“ lines.each { def matcher = (it =~ /IP ([0-9]+.[0-9]+.[0-9]+.[0-9]+)/) while (matcher.find()) { ip = matcher.group(1) } } Jenkins - Unity例 iOS 前ページで作成した仮想インターフェース名
  185. 185. © SEGA rvictlを終了(Pipeline) def rviEnd = "rvictl -x ${params.IPHONE_UUID}".execute() rviEnd.waitFor() Jenkins - Unity例 iOS 終了を忘れると仮想インターフェースが残ってしまうので注意
  186. 186. © SEGA • iOS14からマルチキャストでの通信に強い制限が 掛かった  Multicast Networking Entitlement申請が必要  更に端末側でのローカルネットワーク設定の許可も • Unityのデバッグパケットも上記対応をしないと キャプチャできない 補足 - iOS14からの注意事項 iOS
  187. 187. © SEGA • マルチキャストを使わずに端末側からMacOS側 へ送信するような処理を自前で実装する必要が ある • HTTPでMacOCに向け通信を行うのが楽  MacOS側にサーバを用意しなくても送信パケットを キャプチャすればOK 補足 - iOS14からの注意事項 iOS
  188. 188. © SEGA • VPN接続しているとrvictlでキャプチャできない  VPNで生成された仮想インターフェース側にパケット が流れてしまう • 環境はVPN不要なネットワーク上に構築しよう  scrcpyもQuickTimePlayerもミラーリング映像をマ ウスで操作できるので、いざという時でもVPN越しに 端末の操作を行うことが可能 補足 - VPN環境下の問題

Notas do Editor

  • Android/iOS 実機上での自動テストをより楽に有意義にする為に
    端末管理・イメージ転送・動画記録等の周辺情報のノウハウ共有
    を始めます
  • 株式会社セガ 開発技術部の廣島です
    主にツールやライブラリの開発をしてきました

    最近はデザイナ向けのGitツールを開発したり、テストの自動化、マルチプラットフォーム対応と言った仕事が中心になっています

    本日は宜しくお願いします
  • 本講演に関する注意事項です
    こちらの講演では撮影、SNSへの投稿は可能となっています。資料も後日CEDILに公開されます

    講演中の質問も可能となっていますので、コメント欄に書き込みをお願いします
    また講演後に Zoomによる質疑応答も行います
  • 本日のアジェンダとなります
    まず自動テスト全体の流れについて、お話をします
    そしてテストとその周辺環境に関してとりあげます
    ここまでを私が担当します

    その後担当を交代して
    具体的な環境構築の説明をしたあとに、運用時に発生した問題とその解決方法を共有します
    最後に今後の展望について話します

    前半部分では、Android/iOSの実機を用いて自動テストを実行する際の
    全体の流れやテスト以外の周辺の環境に関して、私たちが構築した環境を例に挙げてお話していきます
  • まずは私達が構築した自動テスト環境に関して説明します
  • こちらが私達が作った自動テスト環境の構成図になります
    Macと端末だけです、非常にシンプルです
    作成した環境はオンプレミス環境でMacと端末をUSBで接続しています

    テストフレームワークに関しては、このセッション中で補足の説明を行います

  • 本講演ではこの部分、マシンと端末とのやりとりを中心にお話をしていきます
  • 続いて環境構築の際に使用したソフトウェアに関して紹介しておきます
    RPAツールや録画ソフトなどをインストールしています、個々の詳しい内容に関してはセッションの後半でお話します
  • 続いて登場人物を紹介します
    ビルド、端末制御、録画担当のMacです

    iOSアプリケーションののビルドを行う必要がある為、Androidと両立する為にMacを採用しました

    主な役割はアプリケーションのビルド、端末情報の収集、アプリケーションのインストール、起動、ミラーリングした画面の録画を行います
  • 続いてモバイル端末です
    テスト対象なので役割としてはアプリケーションの実行を行います

    ビルドを行うマシンとはUSBによる有線接続
    テストフレームワークとはWi-Fiで通信します
  • こちらが大まかな全体の流れになります
    準備フェーズ、テスト実行フェーズ、終了フェーズに分けて説明していきます
    こちらはAndroid版となります、iOS版とは微妙に差があります
  • こちらがiOS版の流れになります
    Androidに比べ少し工程が増えています
    それぞれのフェーズについて少し掘り下げて説明します
  • 各フェーズについて触れる前に、この講演で扱わない事象に関して列挙しておきます
    Android/iOSのアプリケーションのビルド
    テストの実行そのものに関して
    テスト結果の解析や通知、分析など
    既に多くの方が実践されていますし、多くの講演も行われている事から、この講演では共有しません
  • それでは各フェーズに関して少し掘り下げて説明をしていきます
    まずは準備フェーズです

    準備フェーズでは
    端末情報の取得を行い
    続いてミラーリングの準備を行います、私達が構築した環境ではミラーリングした画像を録画します
    続いてAndroidの場合はここでビルドを行い出来上がったアプリケーションを転送します
    そして録画用のソフトを起動します
    ここまでが準備フェーズです

    補足ですが色が薄くなっている箇所が先ほど説明した本講演では積極的に取り上げない部分です
  • 続いてテスト実行フェーズです、テスト実行フェーズはAndroidとiOSで少し工程が違います

    まずはAndroidから説明します
    アプリケーションの起動を行います
    続いてミラーリングした映像の録画を開始し、テストを実行します
    テストが終了したら、録画を停止し、アプリケーションを終了します
    録画したファイルを所定の位置に移動します

    私達が構築した自動テスト環境では、この工程をテスト毎に繰り返します
  • こちらはiOS版のテスト実行フェーズになります
    Android版との違いは、テスト毎にXcodeビルドを行う点です

  • 最後に終了フェーズになります
    録画用ソフトの終了
    ミラーリングの停止
    そしてテスト結果の解析と通知処理を行って終了となります

    これで私たちが構築した自動テスト環境の流れに関しての説明は終わりです
  • 具体的な環境構築の話の前に、

    なぜ実機によるテストが必要なのか
    テストフレームワークに関して
    オンプレ自前環境 vs クラウドサービス
    自動テストと録画について

    それぞれの項目についてどういった点を考えたのかをお話していきます
  • なぜ実機でテストを行うのでしょうか

    答えは明確で、エミュレーターによるテストだけでは不十分だからです
    端末固有の問題であったり、端末とバージョンで発生する問題であったり
    実機でなければ発生しない問題が存在する為です
  • 私達も今までの開発で

    呼び出した関数がそもそも存在していなかったり、ネイティブで実装されている関数の挙動が変わっていたりしました

    どちらも実際にその端末で問題が発覚するまで、正しく動くと思われていました
    こういった点からも実機でのテストは重要で出来る限り行った方が良いでしょう
  • 続いて、テストフレームワークに関して説明をします
    ちょっと環境構築の話題とは外れるのですが、馴染みの無い方がいるかもしれませんので補足します
  • テストフレームワークの主な役割としては以下のものがあります

    プロジェクトの作成
    スクリプトの作成
    スクリプトの実行
    レポートの出力

    こういった機能があるものが主流です
  • 代表的なテストフレームワークとしては
    .NET向けにNUnit,xunit,MSTest.TestFrameworkなどがあります
    NUnitやxunitはシェアも大きく、情報も多く得られます
    MSTestはMicrosoftがリリースしているFrameworkです
    そして、ブラウザ用のSelemiumであったりモバイル用のAppiumが有名です
  • テストフレームワークを選定する際は、自動化を視野に入れた選定を行う事がポイントです
    例えばAppiumのようにネットワーク経由でテスト操作可能なフレームワークを採用すると環境構築がしやすくなります
  • またゲームの場合は独自のフレームワークを作成している事も多く、ゲームの中に実装されている事もあります

    テストフレームワークの選定や実装を行う際は自動テスト環境の構築までを視野にいれて行う事をお勧めします
  • ここからは自動テスト環境をどこに用意するのかについてお話していきます
  • 最近ではクラウドのテストサービスが多く登場しています
    以前はあまり一般的ではなく、かつ高価だったこともあり
    端末やマシンを自前で用意する必要がありましたが、昨今さまざまなサービスが存在し選択肢は広がっています

    AWS Device Farmなどが有名です
  • 実際に自動テストを走らせる環境として
    オンプレミス上に自前で環境を用意するのが良いのか
    クラウドサービスを利用するのが良いのか

    どういった点で選ぶのが良いかまとめました
  • まずはクラウドサービスの特徴です

    並列実行に強いです
    端末を用意する必要がありません
    さらに最近のサービスですと端末の種類も豊富に用意されています
  • 続いてクラウドサービスのデメリットです
    価格はオンプレに比べ高価です
    また使用可能なテストフレームワークに制限がある事が多いです
    Appiumに対応しているサービスは比較的多くあります

    サービスによっては端末を誰かが使用していると使用できないと言う事もあるようです
  • 続いてオンプレミスの環境の特徴です

    まずは予算的に優位な点
    そして自前のテストフレームワークの採用が可能である点、特にゲームの場合は独自のゲーム内フレームワークを組んでいる場合も多いのではないでしょうか
    続いてテストを実行していない時は別の用途に転用が可能な点もメリットです。
    既にデイリーでビルドを行う環境がある場合などは、新たなマシンを用意する必要はありません
  • 続いてデメリットです
    実機テストと言う点で端末は用意する必要があります
    構築・運用については全て自前です
    さらに構築に関する知識が必要となります

    ただこの知識に関しては
    当講演で解消可能となっています

  • その他の選択肢としてクラウドとオンプレのハイブリッドとして
    ビルドからデプロイまでをクラウドで行いテストのみをオンプレミスで行うと言う方法を考えてみました

    Azure pipelines self –hosted agentを用いて
    チェックアウト、ビルド、XcodeビルドまでをAzurePipieline上で行い、テストは実機を用いたオンプレミス環境で行う形です

    すでにAzure上にビルドなどの環境を用意されていた場合でも、オンプレミスのMacを用意すれば本講演の内容を活用できます
  • 私達はオンプレミスを採用しました

    どういった理由でオンプレミスを採用したかですが

    一つは予算面です。私達が間接部門と言う事も影響が大きかったと感じています

    もう一つはテストフレームワークの問題です
    私達は独自のテストフレームワークを採用していた為に適合しませんでした

    さらに、導入するプロジェクトの秘匿性が高くテスト環境を外に出すリスクが取れなかった事が挙げられます

    以上の3点から私達はオンプレミス環境を採用しました
    ただどちらを選択するかは、プロジェクト毎に判断が必要です
  • ここから、話題が変わってテスト実行中の録画に関してお話します
  • 自動テストを行う際には録画を行う事を強くお勧めします
    録画が無い自動テストを想像してみてください

    ある日通知が飛んできます
    テストAが失敗しました
    通知には呼び出し履歴が添付されています

    なるほど、あそこで落ちたのかよし直そう、とはならないですよね

    まずは不具合を再現しようとしますよね
    しかしエラーを再現するのも一苦労です

    テストを録画する事には再現性の低い不具合の発生手順の確立であったり
    不具合の内容確認の容易性を高めると言った効果があります
    録画とテストは切り離せない関係にあると言っても過言ではないでしょう
  • では実際に自動テストを行う際にどういった手段で録画を行うのか
    以下の4つ手法に関して考えていきます

    ミラーリングした映像を録画する方法
    端末で録画を行う方法
    HDMI分配器を利用する方法
    カメラを用いて直接撮影する方法

    それぞれの方法に関して特徴を上げて考えていきます
  • まずミラーリングです
    メリットとして
    タイトル毎に録画機能を実装しなくても良い点
    録画ファイルの取り回しが簡単
    などが上げられます

    特に録画機能を実装しなくても良い点は、実機でテストを行う事の趣旨からとても重要です
    録画機能のデバッグやテストはどうするのかといった問題が出てきてしまうからです

    デメリットとしては複数端末の同時録画が難しいと言う点を挙げました
  • 続いて端末内で録画を実行する方法です

    メリットとしては複数同時端末の録画が可能です
    デメリットとしては、
    録画機能の実装が必要
    端末ごとにデバッグが必要になるかもしれない、バージョンによって動作が不安定になる事もあるでしょう
    録画したファイルの取り扱いが複雑になるといった点もデメリットと言えるでしょう
    エンコーディングをPCで行う場合は、その部分の自動化も行う必要があります
  • つぎはHDMI分配器を利用する場合です

    メリットは
    環境構築が容易な点です
    タイトル毎に録画機能を実装しなくても良い点

    デメリットとしては
    端末との相性問題や
    端末数分の機器を用意する必要がある点です
  • 最後にカメラによる直接録画です

    メリットは
    環境の構築が比較的容易な点
    実装を行う必要が無い点が上げられます

    デメリットは
    テストと録画データの紐づけを行う必要がありデータの扱いが複雑になります
    また端末数に応じたカメラを用意する必要があります
  • 私達はミラーリングを採用しました

    採用の理由としては
    最も大きな理由はタイトル毎端末ごとに録画機能を実装しなくて良いと言う点
    その他には、録画したデータの取り扱いが一番容易であった点
    複数の端末で実行したいという点

    以上が録画方法にミラーリングを採用した理由になります
  • 端末での録画を行う場合についての補足です

    AndroidはMediaProjectionAPIを利用して実装を行います、iOSではReplayKitを用いて実装します

    どちらも、端末やOSのバージョンなどに気を使いつつ実装する必要があります
  • ここで前半が終わりとなります
    ここまでの内容に関して振り返ります
    テストフレームワークこちらは自動化を視野に選定・実装を行いましょう、ネットワークで駆動する形にすると自動化はしやすいです

    そして自動化環境ですが現在は実機テストを行う為のクラウドサービスなども多く存在しています。
    予算やプロジェクトの状況によって最適な答えは変わります

    そして自動テストと録画の関係ですが、非常に相性が良いです。何らかの形で録画を行う事をお勧めします
  • それでは後半は私、竹原が担当させて頂きます
    軽く自己紹介させて頂くと、自動化やツール、ネットワークまわりが主戦場で、最近ではサウンドにも手を出し始めました、よろしくお願いします
    それではさっそく講演に戻りたいと思います
  • 廣島さんからはテストの全体像や環境構築の前段の話をして頂きました
    ここからは、私、竹原から具体的な環境構築の説明と、運用トラブル事例を紹介させて頂きます
    かなり分量があるので少し駆け足になってしまうと思いますが、よろしくお願いします
  • 具体的な環境構築方法の紹介に入る前に、一点資料の見方について共有です
    私のパートでは Android と iOS の説明が交互に入り乱れています
    資料の右上にどちらのプラットフォームの説明かを表すアイコンを入れておりますのでこれを目印代わりにしてください
  • それでは紹介を始めます
    まずは準備フェーズの各種処理について説明します
  • 最初は端末情報の取得についてです
  • テストを行う前に、ビルドしたアプリケーションイメージを実機に転送し、起動しなければいけません
    この転送・起動には、Android ではデバイス名と端末固有のデバイス ID が、 iOS ではデバイス名とこちらも端末固有の UUID が必要となります
    テストフレームワークによっては端末と通信を行う IP アドレスも必要になると思いますので、そういった場合はこのタイミングで取得しておくと楽です
  • それでは、 Android の端末情報の取得についてから説明していきます
    Android は開発用ツールである adb のコマンド結果をパースすれば OK です
    デバイス名、 ID は adb devices を l オプションつきで実行すると一覧が列挙されるので、ここからテストしたい端末をパースします
    IP アドレスは取得したデバイス ID を用いて shell ip addr show オプション付きで呼び出した結果をパースします
  • 私たちは MacOS 上に Jenkins で環境を構築しましたので、当講演では具体例として Jenkins 上で実行する groovy スクリプトや shell を紹介します
    こちらのページは Jenkins の Extended Choice Parameter Plugin を利用してビルドパラメータで端末IDを選択可能にした groovy 例です
    右上にあるような形で端末名を選択してテストを実行可能になります
    スクリプトの詳細は残念ながら説明する時間がありませんので、スキップさせて頂きます
    これから紹介するスクリプトも詳細は追わずに同様にスキップしていきますので、興味のある人は資料公開後確認してみてください
  • こちらは IP アドレスの取得例ですが、一点注意事項があります
    VPN 等仮想インターフェースに IP アドレスが割り振られている場合、 Ip addr show の表示結果が変わります
    構築する環境に合わせてこの辺の実装は修正してください
  • 次に iOS の端末情報取得方法です
    デバイス名、 UUID は xcrun コマンドをパースすることで取得できます
    しかし、 iOS では MacOS から shell を使って直接 IP アドレスを取得する方法がありません
    いくつか解決手段はありますが、 Bonjour の利用をお勧めします
  • Bonjour は MacOS や iOS に標準で搭載されている、Multicast DNS を利用した、デバイス名をホスト名のように扱ってアクセス可能にする仕組みです
    Bonjour を使うと、デバイス名.local で名前解決を行い、アクセスすることが可能になります
    デバイス名は先ほど xcrun をパースして取得しているので、自動化環境への組み込みも簡単です
  • Bonjour を環境に組み込むには
    自前で Bonjour を実装し IP アドレス取得しておくか
    Bonjour 対応アプリを MacOS 側で起動しておくかのいずれかの対応を行う必要があります
    自前実装はしんどいですし、対応アプリは起動しておくだけで OS 側が デバイス名.local を自動的に名前解決してくれるようになり非常に楽なので、対応アプリを起動しておく方をお勧めします
    対応アプリには、このスクリーンショットのような「ミュージック」が該当します
  • とても便利な Bonjour ですが、注意事項も存在します
    まず、iOS に デバイス名.local でアクセスする場合は同一 LAN 上に端末と Mac が存在している必要があります
    また、ActiveDirectory と併用する場合は、ActiveDirectory 側のローカルドメイン名に .local を使わないよう注意する必要があります
  • 非同一 LAN 環境、例えば端末が接続されている Wi-Fi と Mac が接続されているネットワークのセグメントが異なるような社内ネットワークで環境構築をする場合は Bonjour は利用できません
    この場合代替手段として、 MacOS 上で USB 接続されている iOS 端末のパケットをキャプチャし、その結果をパースすることで IP アドレスの取得を実現できます
    特殊な環境、且つ長くなる為にここでは説明を省きますが、詳細を Appendix として資料末尾に記載していますので気になる人は後程ご確認ください
    具体例として Unity アプリケーションでの IP アドレスの取得について掲載してあります
  • こちらは iOS の端末情報取得の Jenkins 例です
    この実装で Android 同様に Extended Choice Parameter でビルドパラメータ化することができます
    そして、ここで取得したデバイス名をもとに、ネットワーク接続が必要になった場合は .local を付けてテストを行います
  • 次は端末上の映像のミラーリング方法を紹介します
  • Android のミラーリングですが、公式にミラーリングソフトがない為に OSS やフリーのツールを活用します
    私たちはこれらの OSS やツールを検証しましたが、最終的には scrcpy を採用しました
    ApowerMirror は録画機能があったりと魅力的だったのですが、GUI 操作が必要な箇所が多く、自動化と相性が悪かったので諦めました
    その他のものは、更新が停止していたり、Mac 版のクライアントソフトが存在しなかったりした為に選択から外れました
  • scrcpy は Apache License 2.0 で公開されている OSS です
    Shell から操作可能で、オプションでビットレートやフレームレート等様々な設定が可能です
    また、端末側に scrcpy のインストールが不要なので自動化とも相性が良く、USB からミラーリングを行えるので挙動も安定しています
    ミラーリング映像のタッチ操作機能もあり、これによりリモート環境越しに端末の操作を行うことが可能で、自動環境構築時のデバッグが捗ります
  • そんな便利な scrcpy ですが、弱点もあります
    音声ミラーリングの機能はありません、後述する別の OSS を利用する必要があります
    録画機能はあるものの、無圧縮で録画する為に自動化環境で用いるには後段でエンコーディングを行う等しないと、ディスク容量が厳しくなる可能性があります
    最後に、コマンドで起動後、この動画のように処理が返ってこないので MacOS 上の Jenkins で使うには少し工夫が必要です
  • こちらが scrcpy を Jenkins で使う為の工夫です
    3 通りあります
    ProcessTreeKiller から逃れる Pipeline で並列化して scrcpy のジョブが処理終了まで終わらないようにする
    AppleScript を使って Jenkins から切り離す
    これらの中で ProcessTreeKiller から逃れる方法が一番簡単なので、今回はその設定方法を紹介します
  • Jenkins は、ビルド中にジョブによって生成されたプロセスを確実に強制終了するためにプロセスを記憶してジョブ完了時に kill する ProcessTreeKiller という機能を持っています
    この ProcessTreeKiller のせいで、 nohup を指定してプロセスをバックグラウンド実行したとしても、ジョブ完了時にそのプロセスは終了してしまいます
    では、どうすれば ProcessTreeKiller を抑制できるのでしょうか?
  • shell でジョブを実行している場合、環境変数の BUILD_ID に dontKillMe プロセスパス を入れることで回避可能です
    その後 nohup を付けてバックグラウンド実行することで scrcpy のような終了を待つプロセスを Jenkins から切り離す形で起動することができます

  • Pipeline の場合は BUILD_ID の代わりに JENKINS_NODE_COOKIE に dontkillMe を設定することで回避可能です
    この場合プロセスパスの指定は不要です
  • ProcessTreeKiller の問題が片付いたので、次は Android で音声もミラーリングする話です
    音声ミラーリングには、 sndcpy という scrcpy とセットで使う為に作成されている OSS を使います
  • sndcpy は内部的に Android 10 から実装された AudioPlaybackCapture API を使用しています
    この為、 Android 9 以前の OS の端末では音声ミラーリングはできません
    また、scrcpy と違って端末にアプリケーションのインストールが必要です
  • sndcpy は同リポジトリ上に同梱されている sndcpy という同名の shell を叩くことで端末へのインストールをはじめとする一連の流れを全て実施してくれます
    流れをざっと説明すると、
    1. sndcpyを端末へインストール
    2. 端末上で sndcpy 起動
    3. 端末側で音声ミラーリングの警告ポップアップが出る、これは AudioPlaybackCapture API を使った際に Android OS 側が出すものです
    4. ポップアップを閉じる
    5. PC 側で VLC というフリーのソフトを起動する
    という感じです
    5 の VLC は、 音声ミラーリングをしたストリームデータを MacOS 側に繋げる役目を担っています。この VLC も別途インストールする必要があります
    そして、この中の 4 が曲者で、表示されるポップアップの「今すぐ開始」を手動で選択をしてあげる必要があります
    これは Android 側の GUI の操作なので自動化と非常に相性が良くない挙動です
  • どうにかこのポップアップを表示しないようにしたいのですが、前述した通りポップアップは Android OS 側が握っているものなので、抑制する方法が見つかりませんでした
    そこで、最終手段である RPA ツールの Automator を用いて自動で GUI 操作を行うことにしました
  • Automator はユーザのデスクトップ操作を記録して再現可能な所謂 RPA ツールで、MacOS に標準搭載されています
    記録後はアプリケーションとして保存することが可能で、とても取り回しが良いです
    内部的には AppleScript というスクリプトで構成されています。AppleScript については次のページで解説します
    これだけ聞くととても便利そうなツールに見えますが、RPA ツールの宿命であるレイアウト変更、例えばボタンの位置が変わったり、ウィンドウのサイズが変わったり、というようなものには弱いです
    ボタンについては座標で記憶せず内部的な名前で処理する等かなり頑張っている感はありますが、それでも先ほど挙げた Android の画面内の GUI を操作する、というような座標で記憶するしかないような操作に関してはどうしても限界があります
    この弱点が最終手段と称したゆえんです
  • Automator の実例に入る前に、実装スクリプトである AppleScript について理解しておくと、作成した Automator アプリケーションの挙動を修正したい場合に役に立ちます
    AppleScript は Apple 製のスクリプト言語で、Automator 経由でアプリケーション化したり、shell から呼び出すことが可能です
    できることは Automator と同等で、キーボードやマウス操作等をスクリプトから実現可能です
    具体的なコードは後程登場しますのでそちらを参考にしてみてください
  • とても便利な AppleScript ですが、世の中に使い方の資料があまり多く出回っていないのが弱点です
    オンライン上にある公式ドキュメントは情報が古い部分があるので、困ったら MacOS 上で AppleScript を開いた際のメニュー「用語説明」の解説も参考にしてみてください
    Quick Time PlayerのAPI等様々なヘルプも記載されています
  • また、画面ロック中は当然キーボードやマウスの操作は意図した通りに動きません
    セキュリティ的に画面ロックを行いたい場合は、該当処理の前後で画面ロックを解除、再ロックの処理を挟む必要があります
    このあたりの問題も、先ほどのレイアウト変更に弱いのとあわせて、RPA ツールが自動テストに向いていない点となります
    ちなみに、画面ロックの自動化は MacOS の Remote Desktop 機能に対応した AppleScript を用いると実現可能です
  • それでは Automator と AppleScript、どう使い分けるのが良いのでしょうか?
    まず、特定のキーをストロークするような簡単な処理であれば AppleScript で実装してしまうのが手っ取り早いです
    アプリケーションを立ち上げて、マウスで特定のボタンを押して画面操作を進めるような複雑な処理の場合は AppleScript での実装はしんどいので Automator を活用しましょう
    また、Automator では記憶した操作をあとで AppleScript として修正することが可能です 記憶時に失敗して複雑な操作を何度もやり直すような面倒な手間が避けられるのでとても便利です
  • それでは、本題に戻って Android のポップアップのボタンを Automator で押しているところをお見せします
    scrcpy をアクティブにして「今すぐ開始」にカーソルを合わせクリック、という操作が行われています
  • こちらがこの自動操作を Automator で開いた際の画面です
    Automator 上では先ほど記憶した操作がこのように分解されています
    このうち、「ATCウィンドウを手前に表示します」という項目は、ポップアップの「今すぐ開始」を押した操作になります
    Android 内の GUI 操作なので Automator 的にはボタンも何もないウィンドウをクリックしたとみなし、このような説明文になっています
  • この Automator の画面から、先ほど触れた AppleScript 化しての修正を行うことが可能です
    まず対象項目を画面下にドラッグ&ドロップすることで、イベントウィンドウに記憶された各種操作をコピーして編集可能にできます
  • コピー先の修正は、各種操作の項目が元々あったイベント欄のものには反映されないので注意してください
    更に各種操作の内容はこのコピー操作を通じてしか変更できません
    つまり、元々のイベント内の各種操作の項目の内容は直接変更できません
  • ですので、記憶した操作を編集したい場合は、イベントウィンドウにあるすべての操作項目をまずはコピーし、
    イベントウィンドウ内の各項目はイベントウィンドウごと削除しておきましょう
  • 説明の為に既に前のページでは編集を行ってしまっていますが、こうした形で各項目のコピーを作成してから AppleScript 化されたものを編集していくのがお勧めです
    修正後は、金づちアイコンをクリックすると構文の強調表示を行ってくれますので、そこからスクリプトが間違っていないかチェックしましょう
    画面は Automator を立ち上げてから、操作開始するまでの待ち時間を 2.2 秒から 1 秒に修正した例です
  • 無事 Automator アプリケーションの作成と修正ができました
    自動処理では、このアプリケーションのポップアップ操作が完了してから次の自動処理に進む必要があります
    しかし、shell からこのアプリケーションを呼び出す場合、open コマンドでは終了を待つことはできません
    この問題を回避する為に、Automator アプリケーションの終了を待つ AppleScript を作成しました
  • こちらがその AppleScript です
    引数で受け取ったコマンドを実行し、そこで立ち上がったプロセスが終了するまで repeat ループで待機します
    AppleScript はこうした処理を手軽に書けるので、使いこなせるようになると自動化が非常にはかどります。お勧めです
  • それでは作成した Automator アプリケーションの処理を先ほどの sndcpy shell の間に差し込みましょう
    Automator での操作はポップアップを閉じるだけに留めたいので、その他の処理はもとの sndcpy スクリプトを分割して対応しました
    後半の VLC に関する処理を独立させ、前半はそのままという形で分けています
  • こちらは分割した sndcpy スクリプトの 1~3 の部分となります
    気になる方は後でご確認ください
  • こちら後半部です
    こちらも気になる方は後でご確認ください
  • 準備が整ったのでいよいよ Jenkins でミラーリング処理の自動化を行います
    まず scrcpy をバックグラウンド実行で呼び出します
  • sndcpy は前述した通り三段階に処理を分けて呼び出します
  • 最後に MacOS 上ではなく Windows 上でミラーリングを実現したい場合の補足です
    scrcpy/sndcpy は Windows にも対応しているので基本的には今まで紹介した処理を bat 化するだけで実現可能です
    Windows には Automator はないので、ポップアップの抑制は別の Windows 対応の RPA ツールを使いましょう
  • ようやく Android のミラーリングの説明が終わりました……
    この調子でどんどん進めていきますので、気になるところがあった方は後日資料を見返して頂ければと思います
    さて、iOS は MacOS に標準にインストールされている QuickTimePlayer でミラーリングが可能です
    QuickTimePlayer を使った自動化については何点かはまり処があるので紹介します
  • まず、Quick Time Player はミラーリングに加え、ミラーリングした映像を録画することが可能です
    しかし、scrcpy 同様に録画ファイルが無圧縮なので自動化 PC のディスク容量を気にする場合はエンコーディングが必要となります
    詳しくは後述する録画の項目で解説します
  • また、これまた scrcpy 同様に、ミラーリングした映像からマウスで操作が可能です
    ただ、 shell からの起動オプションが用意されておらず、キーボードショートカット操作もあるものの肝心のミラーリング操作において対応していないものがあったので、今回の自動化との相性はあまりよくありません
    しかし、他に自動化に使えるミラーリングツールが見つからなかった為、最終的に Automator を使って QuickTimePlayer を操作することにしました
  • こちらが作成した Automator アプリケーションの様子です
    sndcpy のポップアップクローズより若干処理が多いですが、内容的にはシンプルで、
    QuickTimePlayer を起動、アクティブにし
    その後キーボードショートカットにより新規ムービーの作成を起動します
    録画ウィンドウが開いたらミラーリング対象のデバイスを選択します
    これにてミラーリングが開始されます
  • Automator でアプリケーション化できてしまえば jenkins での処理実行は簡単です
    いつもの通り dontkillme 設定をして作成したアプリケーションを呼び出しましょう
    sndcpy の際は処理が完了するのを待ちましたが、ミラーリングの開始は後段にいろいろな処理を挟むので、待たずに投げっぱなしにしています
    気になる人はポップアップクローズ待ちと同様にスクリプト経由で呼び出してください
  • 実は、先ほど紹介したスクリプトでは Automator で操作記録時にミラーリングする端末を決め打ちで指定しているので、一つの Mac に複数のデバイスを接続しているような環境に対応できません
    端末毎に Automator で操作記録するのは現実的ではありませんから、 Android のようにミラーリングするデバイスを選択できる必要があります
  • 順当に考えると、 Automator アプリケーションにミラーリングする端末名を渡して、それを選択するようなスクリプトを作成すれば問題は解決できそうです
    しかし Automator アプリケーションは自分達が調べた限りは引数としてファイルパスしか渡せないようでした
    そこで、 引数で端末名を渡す方式は諦めて、呼び出し元で環境変数に設定したデバイス名を AppleScript 内で読み込むことにより対応しました
  • こちらが修正した AppleScript です
    元の実装では Automator で記憶した際に使っていたデバイス名が埋まっているので、これを動的に呼び出し元から差し替えられるようにします
    修正後の実装では、環境変数 DeviceName にデバイス名が export されているものとして読み込み処理を行い、元の実装のデバイス名の部分に差し込みます
  • 複数デバイス版の Automator アプリケーションに対応した Jenkins ジョブはこちらです
    ノーマル版に、デバイス名を環境変数として指定する処理を挟むだけの非常に簡単な修正で済みました
    ただし、先ほどのスクリーンショットに写っていたデバイス名ひらがなの あいふぉん は文字コードの関係で、そのままでは正常に動作しません
    なるべくアルファベットのデバイス名で環境を構築するのをお勧めします
  • 次はアプリケーションイメージを端末へ転送する処理です
  • Android ではアプリケーションを端末に転送する処理、端末上で起動する処理をそれぞれ adb によって別々に実行できます
    そこで、ビルド・転送は準備フェーズに実行しておき、起動のみテスト毎に実行することでテスト実行の効率を上げることができます
    テストが増えてくるとこうした細かい処理に掛かる時間が馬鹿にできなくなってきますので、なるべく準備フェーズに処理は逃がしましょう
    逆に iOS ではこのタイミングでアプリのビルドや転送ができないので Android に比べて若干効率が悪くなっていますが、それでも工夫次第では改善することができます
    詳細はテスト実行フェーズにて紹介します
  • android でのアプリケーションイメージの端末への転送はとても簡単で、 adb のコマンドを叩くだけで OK です
  • こちらが Jenkins の実行例です
    先ほどのコマンドのパラメータをビルドパラメータに置き換えただけですね
  • いよいよ準備フェーズ最後の手順である録画にやってきました
  • scrcpy/Quick Time Player の録画機能は前述した通り無圧縮ですので、テストが増えてくるとすぐに録画マシンのディスク容量を食いつぶしてしまいます
    そこで、実運用的にはエンコーディング処理を挟む必要があります
    また、 scrcpy の録画機能は sndcpy と連動しておらず、音を拾うことができないので、録画に音声も含めたい場合には機能不足です
    そこで、別のソフトの検証を行った結果、私たちは OBS Studio を採用しました
  • OBS Studio は録画・配信用の OSS です
    シェルの起動オプションとして、ウィンドウサイズや録画範囲などの細かい指定が可能です
    GUI ツールですが、様々な操作のキーボードショートカットが有り、更にwebsocket経由で操作も可能なので、 自動化との相性も悪くはありません
    scrcpy や QuickTimePlayer と違い、録画と同時にエンコーディング可能なのもありがたいポイントです
    youtube や twitch 等の配信でよく利用されており、更新が非常に活発なのも採用の決め手となりました
  • OBS Studio の基本的な使い方は web 上に公開してくださっている方が多数居るので全体説明は割愛して、自動化に関連する項目だけ紹介します
    まず、OBS はプロファイル単位で種々の設定が可能で、起動時の引数でこのプロファイルの指定もできます
    これにより、自動化用にプロファイルを何種類か作っておき、端末単位で使い分けるということができます
    この際、プロファイルの名前にはデバイス名や ID を指定すると処理が楽になるのでお勧めです
  • 録画を行う画面全体を OBS ではキャンバスと呼び、このキャンバスもプロファイル単位の設定となります
    テストする端末の数が膨大な場合、端末毎にプロファイルの作成するのは大変なので、複数の端末の解像度を包含する大きめのキャンバスを設定しておき、近い解像度やメーカー等で統一しておくのも良いでしょう
    端末によっては録画画面に若干の余白ができてしまいますが、テスト用途なので私たちは気にしていません
    どうしても気になる場合は 出力サイズ変更(ソースサイズ) というウィンドウにキャンバスを合わせる機能があるので、その処理の自動化も行うと良いでしょう
  • OBS では画面全体やウィンドウ単位等様々な録画対象を指定できます
    これはシーンという項目のソースで指定可能ですのでキャンバスと共に忘れずに設定を行いましょう
    画面全体を録画するのは無駄なので、ミラーリングを行っているアプリのウィンドウをソース設定するのをお勧めします
    iOS では QuickTimePlayer のウィンドウ名が固定なのでこれを決め打ちで
    Android では scrcpy の起動時オプションでウィンドウ名を指定可能なので、全ての端末で統一した名前を付けて設定の手間を省きましょう
  • シーンの設定が終わったらキーボードのショートカットを設定しましょう
    websocketを使った操作が理想ではありますが、実装はプログラマでないと厳しいと思いますので、今回はショートカットによる自動化を紹介します
    実際の操作は後程説明します
    また、このショートカットもプロファイル毎なので、プロファイルをあまり細かく分けると設定が煩雑になる点には注意してください
  • 最後に録音関連の設定を行います
    sndcpy で取り込んだ音声を仮想デバイスから取り込むことで OBS 上で録音を実施することができます
    これは SoundFlower というツールを用いると実現が可能です
    SoundFlower のインストール後はシステムの設定及び OBS 上で SoundFlower を忘れずに指定するようにしてください
    ちなみに、 M1 チップを採用している Mac ではこの SoundFlower は動かないとのことなので BlackHole というツールを使うと良いらしいです
  • さて、事前準備が終わったのでいよいよ起動設定を行いましょう
    OBS は起動時の引数に --startrecording を指定すると、起動後自動で録画開始することが可能です
    また、先ほどから出てきているプロファイルの指定は --profile “name” で指定できます
    他にも色々指定可能なので、気になる方は公式のドキュメントを参照ください
  • ここまでの内容を落とし込んだ Jenkins のジョブはこのような感じになります
    私達が構築した環境では、先ほど触れたようにテスト毎に OBS を起動するコストを回避する為に起動と録画開始は切り離しており、このタイミングでの録画開始はしていません
  • OBS は Windows にも対応している為、Mac ではなく Windows 上に環境が欲しい場合も同様の手順で構築可能です
    Windows ではキーボード操作の自動化が可能なフリーのソフトが数多くあるので、ショートカットキー操作の自動化も簡単です
  • ただし、Windows で録画環境を作成する場合はロック中やRDPで運用しているPCの録画をどうするか、という問題があります
    この問題は本筋から外れるので Appendix として資料の一番後ろに解決方法を共有してあります
    Windows で環境構築する場合は参考にしてみてください
  • 長かったですがようやく準備フェーズが完了しました
    あとはテストをまわすだけ、といいたいところですが、アプリケーションの終了を挟まずに起動を継続したままテストを実行すると「別のテストの後に実行すると前提条件がクリアされて成功してしまうバグ」のような問題を踏んでしまう恐れがあります
    よって、テスト間で依存関係がない限りはテスト実行毎にアプリの起動・終了を挟む方が安全です
    ここからはこのテスト毎の実行環境の構築方法について共有します
  • まずはアプリケーションの起動からです
    アプリケーションの起動は Android と iOS で必要な処理が異なりますのでそれぞれ共有します
  • Android では、アプリの起動は転送の時同様に adb を用います
  • こちらが Jenkins の実行例です
  • 次に iOS のアプリケーションの起動です
  • iOS のアプリケーションを端末で起動するにはビルド、転送の処理も一緒に行う必要がある為、この項目でまとめて紹介します
  • まず、iOS ではアプリケーションの転送、起動に xcodebuild という Xcode のコマンドラインツールを使用します
    xcodebuild には、Xcode 8 から導入された、ビルドのみを行うことが可能な build-for-testing と転送/起動のみを実行可能な test-without-building というオプションが存在します
    これによりアプリのビルドと起動/転送を分けることができます
  • と言いたい所なのですが、test-without-building には連続実行した場合に二回目以降のアプリの起動が失敗する、という問題があります
    これは、xcodebuild が内部的に利用している appium の状態が二度目以降にリセットされていない為に起こる問題のようで、
    面倒なことにソースに変更が無い状態で build-for-testing でビルドし直すだけではこの状態はリセットされず、フルビルドし直す必要があります
  • フルビルドは時間も掛かりますし、テスト毎に実行していては全てのテストが完了するまでに何時間あっても足りません
  • そこでなんとか回避方法が無いか調査したところ、Xcode のキャッシュ内に生成された .app を削除して build-for-testing した後に test-without-building でアプリ起動することでこの問題を回避できることが分かりました
    この手順を踏んだ場合、 build-for-testing 実行時には .app が再生成されるだけとなり、フルビルドに比べて掛かる時間も非常に短くて済みます
  • Xcode にキャッシュされた .app のパスはこちらです
    パスに埋まっているハッシュ値については、動的に取得する方法が見つかりませんでしたので、この値については一度手動で Xcode でビルドしてあげて、確認する必要があります
    一度ビルドを行ってしまえばこの値は変わることはないようなので、頻繁に値を更新するような手間は不要です
  • ただし、 test-without-building を使う為には xcodeproj 内に Xcode のテストである xctest が存在している必要があります
    build-for-testing 付きで xcodebuild を実行すると、この xctest が端末上で実行されるので、
    何もせずに永久に待機し続ける xctest を作成、実行することにより疑似的にアプリの起動を再現することが可能です
    永久に待機するので、テスト終了時にはアプリを強制停止するしかなく、xctest のテスト結果は常に失敗することになりますが、アプリの起動に利用しているだけなのでこの結果は無視しましょう
    xctest についての詳細は世の中に数多く出回っておりますので、今回の講演では割愛させて頂きます
  • こちらが今まで紹介した手順のビルドの個所を Jenkins上 で実行している例です
  • こちらが転送・起動です
    どちらも気になる方は後でご確認ください
  • 最後に補足です
    未検証ではありますが、現在β版である Xcode13 には
    -test-itreations というテストの回数を指定可能になるオプション
    -retry-tests-on-failure という失敗したテストをリトライ可能になるオプション
    -run-tests-until-failure という成功するまでテストを繰り返すオプション
    が追加されるようです
    これらをうまく使えば .app を削除してビルドし直す、といった面倒な手間は不要になりそうなので期待しています
  • もう一点補足です
    xcodebuild を使わずに GUI 版の Xcode からキーボードショートカット経由で転送/起動を実現することも可能です しかし、RPA ツールでの自動化はこれまでお話したように最終手段であり、他の解決方法がある場合はなるべくそちらを採用するのをお勧めします
  • いよいよテスト実行に近づいてきました……
    このままブレイク無しで突っ走りますので、あと少しお付き合い頂ければと思います
    というわけで録画開始処理に関する共有です
    Android ではこの位置ですね

  • iOS はこの位置の処理です
    録画開始は iOS と Android で共通の処理となります
  • というわけで録画開始処理に関する共有です
    準備フェーズで OBS に設定した録画開始のショートカットを押せば終わりなのでとても簡単です
    単純なキーストロークのみでいいので、ここは Automator ではなく AppleScript を直接使います
  • AppleScript でキーストロークするのはとても簡単です
    AppleScript の仕様を知らないでもこのスクリプトを見るとなんとなくやっていることはわかるのではないでしょうか
    Jenkins からもこの shell を実行すればそれだけで OK なので、実例は割愛させて頂きます
  • いよいよテストの実行にやってきました
    後の処理は Android/iOS 共通となりますので、iOS 側の図の紹介は割愛させて頂きます
  • 最初にお伝えした通り、今回の講演ではテストの実行そのものは共有の対象外ですが、少しだけ補足させてください
    テストの実行開始は、どんなテストフレームワークを採用しているかでタイミングが異なります
    起動したアプリケーションに対して、外部からテストの実行を行うものを採用している場合、端末側のアプリケーションと MacOS 側テスト関連の準備が整ったこのタイミングになってからテストの実行を開始する必要があります
  • 私たちが採用しているテストフレームワークも通信を行うタイプだったので、このタイミングでテストを実行開始しています
    具体的には、起動している端末側のアプリケーションに対してテストフレームワークを経由してテストしたい動作を Json で指定します
    アプリケーションには侵入型のテストサーバプログラムが仕込まれており、テストフレームワークから受け付けた動作を実行し、その結果を返します
    テストフレームワークは返ってきた結果からテストの成否を判定します
  • それでは、非通信型のテストフレームワークの場合はどうでしょうか?
    アプリの起動時にオプションで指定するようなものの場合も Android/iOS 共に指定が可能です
    adb は引数オプションが有ります
    xcodebuild はプリプロセッサマクロを活用すれば実現可能です
    コンフィグファイル等、テスト用のファイルを読み込んで実行する場合は、テスト毎に端末側にファイルを転送したり、特定のフォルダ下のファイルに対してファイル毎にテストを実行するように環境構築すると良いでしょう
  • テストが終了したらテスト毎の後始末を行いましょう
    まずは録画を停止させます
  • 録画終了は起動同様に AppleScript でキーストロークを行います
    こちらも同様にこの shell を Jenkins から呼び出せば OK ですが、 OBS は録画終了ボタンを押しても動画のエンコードの関係で即座に録画が終了しないこともあるので、自動化の際は次の処理に移行するまでに少しウェイトを入れてあげると良いです
  • 次にアプリを終了してあげます
  • Android は開始同様に adb で終了させます
  • こちらが Jenkins の実行例です
  • iOS アプリは起動を行った xcodebuild を pkill してあげましょう
    そのままなので Jenkins ジョブは割愛します
  • 後片付けが終わったら録画ファイルのリネームを行います
  • OBS はファイル名を柔軟に変更できますが、起動時引数のようなものでファイル名にテストの名前を埋め込むようなことはできません
  • 動画ファイルにテスト名やその実行日時が埋め込まれていると、結果を確認している際に非常に分かり易くなります
    そこで、テスト終了毎に録画したファイル名にテストの名前を付ける形でリネームしています
    こちらの mv を使った例は動画ファイルを Jenkins の成果物として保存したいのでついでにフォルダの移動もしてしまっています
  • これにてテスト実行フェーズは完了です
    あとは全体の後始末を行いましょう
  • まずは OBS の後始末を行います
  • OBS は pkill で終了すれば OK です
  • ミラーリングの終了も
  • scrpcy は pkill を
    sndcpy はアンインストールをしてあげます
  • QuickTimePlayer も pkill で OK です
    これで後始末も完了です
    お疲れ様でした
  • と言いたいところですが、もう少しだけ続きますのでお付き合いください
    当項目では、これまであげた環境を実際に運用してみて発生した問題とその解決方法を共有します
  • まず OS アップデートのポップアップ通知がテスト実行フェーズのループ中に入り込んで操作不能になる問題です
    Android/iOS 共にアップデートの抑制は可能ですので、面倒ですが端末毎に設定を忘れずに行っておきましょう
  • 次は Automator の操作が時々失敗する問題です
    こちらは Automator で記録した際の設定、例えばウェイト値が状況によっては不十分だった為に発生する、RPA ツールではよくある問題でした
    前述した通り、 Automator は AppleScript として修正可能ですので、テスト結果が安定しない場合はパラメータを変更する等細かい調整を行いましょう
  • 次は、ノッチ対応のアプリを録画したら録画映像に妙な余白が発生した問題です
  • こちらは余白は問題ではなく、単純にノッチ対応でアプリケーションの描画対象外になっている部分も込みでミラーリングされていただけ、という落ちでした
    この余白があるイコールノッチ対応の実装がうまくいっている、ということでもあるので、期せずしてミラーリングを用いた自動化環境では、録画データからノッチ対応の確認も行うことができることが分かりました
  • 最後に、解像度の異なる端末でテストをした際に sndcpy のポップアップクローズが失敗する問題です
    この動画は分かり易さの為に少し極端に解像度を変えていますが、解像度の異なる端末で共通の Automator アプリケーションを用いるとこの問題が発生すると考えてください
    ミラーリングする解像度を合わせるような対策を行えば端末共通で Automator アプリケーションを使えますが、当然元の解像度が異なる場合はアスペクト比が崩れてしまいます
    とは言え、端末毎に Automator で操作を記憶するのは手間が現実的ではないのでどうするか悩ましい所です
    これは現状も解決できていない課題で、「今すぐ開始」を画像認識して押すようなアプローチが必要なのではないか、と考えています
  • それでは、当環境の展望です
  • まず、一端末ずつテストを実行すると時間が掛かってしまうので、複数端末を並列でテストしたいという要望があります
    録画をどうするかが課題ですが、OBSのキャンバスをうまく活用すればいけるかも?と検討中です
    また、テスト中のパフォーマンスを取得したい、という話もあがっております
    こちらは端末ミラーリングの負荷の影響がどうしても出るので純粋な負荷をどう取得するのか、録画を切ればいけそうですがそれでいいのか等の検討を行っています
  • 当講演の内容は以上となります
    駆け足になりましたがご清聴ありがとうございました
    当講演を聞いて、実機の自動化やってみようかなと思って頂けたり、困っていることのヒントが得られたようでしたら何よりです
    また、私たちの環境もまだまだ試行錯誤の途中ですので、他にもっと良いやり方があるようでしたら是非ご教授頂ければ嬉しく思います
    それでは皆様、良い実機テストライフをお送りください!

×