$30 off During Our Annual Pro Sale. View Details »

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

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

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

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

SEGADevTech

July 15, 2022
Tweet

More Decks by SEGADevTech

Other Decks in Programming

Transcript

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

  2. © SEGA ⽬次 - Android Android 端末情報の取得 ミラーリングの準備 Androidビルド アプリを転送

    録画用ソフトの起動 アプリを起動 ミラーリング映像の録画開始 テストの実行 ミラーリング映像の録画停止 アプリを終了 録画ファイルのリネーム 録画用ソフトの終了 ミラーリングの停止 結果の解析と通知処理 準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
  3. © SEGA ⽬次 -iOS 端末情報の取得 ミラーリングの準備 録画用ソフトの起動 録画用ソフトの終了 ミラーリングの停止 結果の解析と通知処理

    準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ iOS XCodeビルド アプリを転送・起動 ミラーリング映像の録画開始 テスト実行 ミラーリング映像の録画停止 アプリの終了 録画ファイルのリネーム
  4. © SEGA ゲームコンテンツ&サービス事業本部 技術本部 開発技術部 廣島 岳史 ⾃⼰紹介 SEGA⼊社後 アーケード向けのライブラリ開発やツール作成などに従事

    最近ではプランナー・デザイナに向けたGitHubEnterprise⽤のツール の作成やUnity向け⾃動テスト⽀援ソリューションを開発しています
  5. © SEGA • 本講演内容の撮影、SNS投稿は OK • 後⽇、CEDIL で資料を公開 • 講演中も質疑が可能です。

    コメントに書き込んでください • 講演後にZoomによる質疑応答を実施 • 資料に記載されている会社名、システム名、製品名、サービス名は各社の登録商標または商標です • Android ロボットは、Google が作成および提供している作品から複製または変更したものであり、 クリエイティブ・コモンズ表⽰ 3.0 ライセンスに記載された条件に従って使⽤しています
  6. © SEGA • ⾃動テスト全体の流れ • テストとその周辺環境に関して • 具体的な環境構築の説明 • 運⽤時に発⽣した問題とその解決⽅法の共有

    • 今後の展望 アジェンダ
  7. © SEGA ⾃動テスト環境の構成

  8. © SEGA 構築した⾃動テスト環境の構成図 USB テストフレームワーク 通信による操作 パラメータ送受信 テストの実行 ネットワーク

  9. © SEGA 本講演で取り上げる部分

  10. © SEGA 使⽤しているソフトウェア ミラーリング (Android) sndcpy サウンドのミラーリング用のソフトのみ ミラーリング (iOS) Quick

    Time Player ミラーリング (Android) scrcpy VLC RPA Automator 録画 OBS Studio
  11. © SEGA ビルド&端末制御&録画担当(Mac) アプリケーションのビルド 端末へのアプリケーションのインストール 端末情報の収集 テスト画面の録画 iOSアプリのビルドを行う事からMacを採用 Macのバージョンは Big

    Sur : 11.4 使用しているMacは Intel CPU
  12. © SEGA モバイル端末 (iOS / Android) 主な役割 アプリケーションの実行 テストフレームワークとの通信 ビルドマシンとはUSBを用いて接続

    テストフレームワークとはWi-Fiで通信
  13. © SEGA 全体の流れ(Android) Android 端末情報の取得 ミラーリングの準備 Androidビルド アプリを転送 録画用ソフトの起動 アプリを起動

    ミラーリング映像の録画開始 テストの実行 ミラーリング映像の録画停止 アプリを終了 録画ファイルのリネーム 録画用ソフトの終了 ミラーリングの停止 結果の解析と通知処理 準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
  14. © SEGA 全体の流れ(iOS) 端末情報の取得 ミラーリングの準備 録画用ソフトの起動 録画用ソフトの終了 ミラーリングの停止 結果の解析と通知処理 準備フェーズ

    テスト実行フェーズ(繰り返し) 終了フェーズ iOS XCodeビルド アプリを転送・起動 ミラーリング映像の録画開始 テスト実行 ミラーリング映像の録画停止 アプリの終了 録画ファイルのリネーム
  15. © SEGA これらに関してはこの講演では共有しません • Android/iOS アプリのビルド • テストの実⾏ • テスト結果の解析や通知

    共有しない項⽬
  16. © SEGA 準備フェーズ USB 端末情報の 取得 ミラーリン グの準備 ビルド (Android)

    アプリケー ションを転送 (Android) 録画用ソフ トの起動 1 2 3 4 5
  17. © SEGA テスト実⾏フェーズ(Android) USB アプリを起動 ミラーリン グした映像 の録画開始 テストの実 行

    ミラーリン グした映像 の録画停止 アプリを終了 録画ファイ ルのリネー ム 1 2 3 4 5 6
  18. © SEGA テスト実⾏フェーズ(iOS) USB XCodeビルド アプリを転 送・起動 ミラーリン グした映像 の録画開始

    テスト実行 ミラーリン グした映像 の録画停止 アプリを終了 録画ファイル のリネーム 3 2 1 4 5 6 7
  19. © SEGA 終了フェーズ USB 録画用ソフトの 終了 端末映像のミ ラーリング停止 テスト結果の解 析と通知処理

    1 2 3
  20. © SEGA Ø なぜ実機テストが必要か Ø テストフレームワークについて Ø オンプレ⾃前環境 vs クラウドサービス

    Ø ⾃動テストと録画の関係 本題に⼊る前に
  21. © SEGA • エミュレータ―を⽤いたテストだけでは不⼗分 • 端末でのみ発⽣する問題 なぜ実機でテストを⾏うのか

  22. © SEGA Ø そもそも関数が無かった Ø ネイティブの関数の挙動が変わっていた 特定の端末・特定のバージョンで発⽣した 動かしてみるまで分からない 特定の端末で発⽣した不具合

  23. © SEGA テストフレームワークについて

  24. © SEGA • テストプロジェクトの作成 • テストスクリプトの作成 • テストスクリプトの実⾏ • テストレポートの出⼒

    テストフレームワークの主な役割
  25. © SEGA ØNUnit Øxunit ØMSTest.TestFramework ØSelenium ØAppium 代表的なテストフレームワーク ブラウザ .NET

    .NET .NET モバイル
  26. © SEGA • テストフレームワークとアプリケーションが どのようにやり取りをするのかがポイント テストフレームワークと環境構築 テストコード

  27. © SEGA • ゲームでは独⾃フレームワークの場合も多い 環境構築を視野に⼊れる事が重要 テストフレームワークを選定・実装する際 は、自動テスト環境の構築まで視野に入れて 選定を行う事をお勧めします

  28. © SEGA ⾃動テスト環境の準備

  29. © SEGA クラウドのテストサービス 近年端末の種類も豊富なクラウドのテストサービ スが多く登場 ü AWS Device Farmなどが有名 ü

    サービスを介して実機でテストを実行 ü 端末を用意する必要が無い ü 端末の種類も豊富 テストコード
  30. © SEGA • 以前はオンプレしか選択肢は無かった • プロジェクトの都合や予算で判断 オンプレミス vs クラウドサービス

  31. © SEGA • 並列実⾏に強み • 端末を⽤意する必要が無い • 端末の種類が豊富 クラウドサービスの特徴(メリット)

  32. © SEGA • お値段 • 使⽤可能なテストフレームワークに制限がかか る事もある • 他の⼈が端末を利⽤していて使えない事も クラウドサービスの特徴(デメリット)

  33. © SEGA • お値段 • ⾃前のテストフレームワークの採⽤が可能 • テスト実⾏していない時は別の⽤途に転⽤可能 オンプレミス環境の特徴(メリット)

  34. © SEGA • 端末を⽤意する必要がある • 構築・運⽤については全て⾃前 • 構築に関する知識が必要 ü当講演で解消可能︕ オンプレミス環境の特徴(デメリット)

  35. © SEGA ハイブリッド(クラウド+オンプレミス) USB Azure pipelines self hosted agent ビルドからデプロイまでをクラウドで実行

    テストをオンプレミスで実行 Azure Pipelines self –hosted agent を使う
  36. © SEGA • お値段 • 独⾃形式のテストフレームワーク • 導⼊するプロジェクトの秘匿性が⾼くテスト環 境を外に出すリスクが取れなかった オンプレミスを採⽤しました

  37. © SEGA テスト実⾏中の録画について

  38. © SEGA • 再現性の低いバグの発⽣⼿順の確⽴ • 不具合の内容確認の容易性 実機テストでの録画の必要性 Ø 自動テストレポートにテスト動画を含める Ø

    BugTrackingSystemに動画付きで投稿する 効果的な使用例
  39. © SEGA • ミラーリングしたものを録画 • 端末で録画 • HDMI分配器を利⽤する • カメラを⽤いて直接撮影する

    録画⼿法について
  40. © SEGA ミラーリング メリット • タイトル毎に録画機能を実装しな くて良い • 録画ファイルの取り扱いが簡単 デメリット

    • 複数端末同時録画が難しい ミラーリングソフト 録画を行うデバイス
  41. © SEGA 端末で録画 メリット • 複数端末同時録画が可能 • 並列でテストが可能 デメリット •

    タイトル毎に録画機能の実装が必要 • 端末毎にデバッグ • 録画ファイルの取り扱いが複雑 画面を録画 録画データ転送
  42. © SEGA HDMI分配器を利⽤する メリット • 環境構築が容易 • 録画機能を実装しなくて良い デメリット •

    端末との相性問題 • 端末数分の分配器⽤意する必 要がある MHL変換アダプタ HDMI分配器 録画を行うデバイス
  43. © SEGA カメラで録画 メリット • 環境構築が⽐較的容易 デメリット • 録画データの取り扱いが複雑 •

    録画データのエンコーディン グを⾃分で⾏う必要がある • 複数端末分の機材が必要
  44. © SEGA 採⽤理由 • タイトル毎に録画機能を実装しなくて良い • データの取り扱いが容易な点 • 複数端末での実⾏が可能な点 が決め⼿になりました

    ミラーリングを採⽤しました
  45. © SEGA • Andoroidでの録画⽅法 – MediaProjection APIで録画 – REQUEST_MEDIA_PROJECTIONなどの権限 が必要

    • iOSでの録画⽅法 – ReplayKit について 端末での録画を⾏う場合(補⾜)
  46. © SEGA 前半まとめ テストフレームワーク 自動化を視野に選定・実装しましょう 自動化環境 クラウドサービスも多く存在します 録画 自動テストと録画は相性◎ 積極的に利用しましょう

  47. © SEGA ゲームコンテンツ&サービス事業本部 技術本部 開発技術部 ⽵原 涼 ⾃⼰紹介 【登壇歴】 CEDEC

    2020 「技術同⼈作家になろう 〜働き⽅改⾰時代におけるエン ジニアのレベルアップの⼀例〜」 Unite Tokyo 2019 「⼤量のアセットも怖くない︕〜HTTP/2による⾼ 速な通信の実装例〜」 CEDEC 2018、CEDEC 2016、CEDEC 2015 プロダクション関連のラ ウンドテーブル GDC2016 報告会 「GDC16にみる⾃動化技術とテストのトレンド」
  48. © SEGA 具体的な環境構築の流れ

  49. © SEGA • 右上にプラットフォームを⽰すアイコンがあります 資料の⾒⽅ Android iOS

  50. © SEGA 準備フェーズ 端末情報の取得 ミラーリングの準備 Androidビルド アプリを転送 録画用ソフトの起動 アプリを起動 ミラーリング映像の録画開始

    テストの実行 ミラーリング映像の録画停止 アプリを終了 録画ファイルのリネーム 録画用ソフトの終了 ミラーリングの停止 結果の解析と通知処理 準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
  51. © SEGA 端末情報の 取得 ミラーリン グの準備 ビルド (Android) アプリケー ションを転送

    (Android) 録画用ソフ トの起動 端末情報の取得 USB 1 2 3 4 5
  52. © SEGA • 実機へのアプリ転送・実⾏には端末情報が必要 • Android ü デバイス名/デバイスID • iOS

    ü デバイス名/UUID • IPアドレスも必要な場合はここで取得しておくと楽 端末情報の取得
  53. © SEGA • adbコマンド結果をパースすることにより取得 • デバイス名/ID ü adb devices –l

    • IPアドレス ü adb -s “デバイスID” shell ip addr show 端末情報の取得 Android
  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. © 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. © SEGA • xcrunコマンド結果をパースすることにより取得 • デバイス名/UUID ü xcrun instruments –s

    • IPアドレス ü Bonjourの利⽤がお勧め 端末情報の取得 iOS
  57. © SEGA • 対応端末にデバイス名指定でアクセスできる • デバイス名に.localを付けてアクセス ü デバイス名は準備フェーズで取得したものを流⽤ Bonjour iOS

  58. © SEGA • 以下のいずれかで実現 ü ⾃前でBonjourを実装しIPアドレス取得 ü Bonjour対応アプリをMacOS上で起動しておく Bonjourを使ったアクセス iOS

  59. © SEGA • 同⼀LAN内限定 • ActiveDirectoryと併⽤する場合に注意 ü ローカルドメイン名に.localは使わない Bonjour注意事項 iOS

  60. © SEGA • パケットキャプチャをすることで対応可能 ü 特殊な事例且つ⻑くなるので詳細はAppendixで ü Unityの場合の具体例が掲載されています ⾮同⼀LAN環境への対応 iOS

  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. © SEGA ミラーリングの準備 端末情報の 取得 ミラーリン グの準備 ビルド (Android) アプリケー

    ションを転送 (Android) 録画用ソフ トの起動 USB 1 2 3 4 5
  63. © SEGA • 公式のミラーリングソフトは存在しない ü OSS やフリーのツールを利⽤するのが⼀般的 • 検証を⾏ったもの ü

    〇 scrcpy 採⽤︕ ü △ ApowerMirror ü ✖ Androidtool-mac, Vysor, Mobizen ソフトウェアの選定 Android
  64. © SEGA • shell から操作可能 • オプションが豊富 • 端末にアプリケーションのインストールが不要 •

    USB経由でミラーリング可能 • ミラーリングされた画⾯からタッチ操作可能 scrcpyの特徴 Android
  65. © SEGA • ⾳声ミラーリング機能はない • 録画機能は可能だが無圧縮 • コマンドで起動後、処理が返ってこない scrcpy注意事項 Android

  66. © SEGA • 以下の3通りのいずれかで対応可能 1. ProcessTreeKillerから逃れる (お勧め︕) 2. Pipelineで並列化する 3.

    AppleScriptを使ってJenkinsから切り離す scrcpyをJenkinsで使う場合 Android
  67. © SEGA • Jenkinsはジョブ中に起動したプロセスをその ジョブ終了時に強制終了する ü https://wiki.jenkins.io/display/JENKINS/ProcessTreeKiller • nohup &

    を使ってもジョブを抜ける際にアウト ProcessTreeKiller補⾜ Android
  68. © SEGA • shellの場合は環境変数 BUILD_ID に dontKillMe プロセスパス(名) を⼊れて回避 •

    shell設定例 ü export BUILD_ID=dontKillMe scrcpy nohup scrcpy <options> & ProcessTreeKiller補⾜ Android
  69. © SEGA • PipelineはJENKINS_NODE_COOKIEに設定 • Pipeline実⾏例 ü steps { sh

    ''' export JENKINS_NODE_COOKIE=dontkillMe nohup scrcpy <options> & ''' } ProcessTreeKiller補⾜ Android
  70. © SEGA • sndcpyを使う ü scrcpyと⼀緒に使う為に作成されたOSS ⾳声ミラーリングしたい Android

  71. © SEGA • Android 10から使⽤可能 ü 内部的にAudioPlaybackCapture APIを使⽤ • 端末へのアプリケーションインストールが必要

    sndcpy注意事項 Android
  72. © SEGA sndcpyというスクリプト内で以下が実⾏される 1. sndcpyを端末へインストール 2. 端末上でsndcpy起動 3. 端末側でポップアップが出る 4.

    ポップアップを閉じる (⼿動で「今すぐ開始」を押す) 5. PC側でVLCを起動する ⾳声ミラーリングまでの流れ Android ここを⾃動化したい
  73. © SEGA • ポップアップはAndroid側が出しているので抑制 できない • 最終⼿段のAutomatorを利⽤ ü MacOSに標準搭載されているというRPAツール sndcpyカスタマイズ

    Android
  74. © SEGA • ユーザ操作を記録・再現するRPAツール ü アプリケーションとして保存できる ü 内部的にはAppleScript(後述)に落とし込まれる • レイアウトの変更には弱い

    ü なるべく座標指定しないような実装にはなっている Automator Android
  75. © SEGA • Apple 独⾃のスクリプト⾔語 • shellから呼び出し可能 ü shellの先頭に #!/usr/bin/env

    osascript を付ける • キーボードやマウス等の操作が可能 AppleScript Android
  76. © SEGA • 資料が少ない ü オンラインの公式ドキュメントは情報が古いことも • AppleScriptメニュー内にある⽤語説明がお勧め AppleScript注意事項 Android

  77. © SEGA • 画⾯ロック中は操作できないものがある ü キーボード、マウス操作 AppleScript注意事項 Android

  78. © SEGA • 簡単な操作ならAppleScript単体で実装する • 複雑な操作はAutomatorで実装する ü AppleScriptに変換して細部を修正可能 Automator運⽤⽅針 Android

  79. © SEGA ポップアップクローズの⾃動化 Android

  80. © SEGA Automatorで記憶された操作 Android

  81. © SEGA Automatorの修正 Android ドラッグ&ドロップ 項⽬の内容がコピーされる

  82. © SEGA Automatorの修正 Android ドラッグ&ドロップ コピーなので保存してもこの中の項⽬には反映されない これは1個⽬のコピー(編集はコピーしかできない) これは2個⽬のコピー

  83. © SEGA Automatorの修正 Android イベントをここから全部消せる

  84. © SEGA Automatorの修正 Android

  85. © SEGA • ポップアップを閉じたことを確認してから次の 処理に進みたい ü openコマンドでは終了を待てない • Automatorアプリ終了を待つAppleScriptを作成 Automatorアプリの終了を待つ

    Android
  86. © SEGA !"#$!%#&'()*"+,--.-/ !"#$%&#'()#*)+,-%.%/&(01 -),&$),23-4/-55.)36,0&-/*%%4).5*7 1*88,.008(/.1(-),9:*&5().89 3- %/&(01,3-4/-55.)3,() /$&&*)1:.' 3*8.;,<=>

    1*88,.008(/.1(-),9?;%1*5,@+*)1%9 &*0*.1 (A )-1,B*C(%1%,0&-/*%%,0&-/*%%4).5*D,1E*) *C(1 &*0*.1 *)3,(A 3*8.;,<=> *)3,&*0*.1 *)3,1*88 *)3,1*88 *)3,&$) Automatorアプリの終了を待つ Android 引数で受け取ったコマンドを実⾏ 起動したプロセスが存在する限り待つ
  87. © SEGA 1. sndcpyを端末へインストール 2. sndcpy起動 3. 端末側でポップアップが出る 4. ポップアップを閉じる

    5. PC側でVLCを起動する ⾳声ミラーリングまでの流れ Android sndcpyを分割して⾃前のAutomatorの処理を挟む strat_vlc.sh sndcpy Automator処理
  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. © 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. © 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. © 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. © SEGA • scrcpy/sndcpyはWindowsにも対応 ü sndcpy.batを使う等細かい差異はあるが基本同じ対 応で⾃動化可能 • ポップアップの抑制にはWindows対応のRPA ツールで代⽤を

    Windowsでミラーリング Android
  93. © SEGA • Quick Time Playerでミラーリングが可能 ü MacOSに標準インストール • Quick

    Time Player以外の候補は⾒つからず • ⾃動化についてはハマり所がいくつかある ソフトウェアの選定 iOS
  94. © SEGA • Quick Time Playerで録画することは可能 ü ただしエンコーディング無し Quick Time

    Playerでの録画 iOS
  95. © SEGA • ミラーリング映像から操作が可能 • shell経由での細かい実⾏をサポートしていない • 最終的に再びAutomatorに頼ることに Quick Time

    Playerの⾃動化 iOS
  96. © SEGA Automatorでの起動 iOS

  97. © SEGA export BUILD_ID=dontKillMe start_iphone_mirroring nohup open -a start_iphone_mirroring &

    Quick Time Player – Jenkins例 iOS
  98. © SEGA • 複数のiPhoneが接続されている場合、Android 同様に端末を指定したい 複数デバイス対応 iOS

  99. © SEGA • Automatorアプリは起動時引数に制限がある ü ファイルパスしか渡せない • 環境変数にデバイス名を保存しておき、それを Automator内のAppleScriptで読み込む 複数デバイス対応

    - Automator iOS
  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. © SEGA 複数デバイス対応- Jenkins例 iOS export BUILD_ID=dontKillMe start_iphone_mirroring export DeviceName=“devtech-iphone“

    nohup open -a start_iphone_mirroring & Jenkins側は環境変数設定を挟むだけでOK “あいふぉん”のような⽇本語はアウトなので注意
  102. © SEGA 録画⽤ソフトの起動 端末情報の 取得 ミラーリン グの準備 ビルド (Android) アプリケー

    ションを転送 (Android) 録画用ソフ トの起動 USB 1 2 3 4 5 Android
  103. © SEGA テスト実⾏フェーズ Android 端末情報の取得 ミラーリングの準備 Androidビルド アプリを転送 録画用ソフトの起動 アプリを起動

    ミラーリング映像の録画開始 テストの実行 ミラーリング映像の録画停止 アプリを終了 録画ファイルのリネーム 録画用ソフトの終了 ミラーリングの停止 結果の解析と通知処理 準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ ビルド・転送は準備フェーズに実⾏ 起動のみテスト毎に実⾏することで効率アップ
  104. © SEGA • adb.exeを使⽤する ü adb -s “デバイスID” install ”アプリケーションイメージのパス”

    アプリの転送 Android
  105. © SEGA adb -s $ANDROID_ID install $APPLICATION_PATH アプリの転送 – Jenkins例

    Android
  106. © SEGA 録画⽤ソフトの起動 端末情報の 取得 ミラーリン グの準備 ビルド (Android) アプリケー

    ションを転送 (Android) 録画用ソフ トの起動 USB 1 2 3 4 5
  107. © SEGA • 検証を⾏ったもの ü 〇 OBS Studio 採⽤︕ ü

    △ scrcpy/Quick Time Player ソフトウェアの選定 Android iOS
  108. © SEGA • シェルから起動オプションが指定可能 • ほぼ全ての操作のキーボードショートカット有 • websocketによる操作も可能 • 録画と同時にエンコーディング可能

    • 配信でよく利⽤されており更新が⾮常に活発 OBS Studioの特徴 Android iOS
  109. © SEGA • OBSはプロファイル単位で種々の設定が可能 ü 起動時の引数でこのプロファイルを指定できる • ⾃動化⽤にプロファイルを作成しておく ü プロファイル名にIDやデバイス名を使うと楽

    事前設定 - プロファイル Android iOS
  110. © SEGA • プロファイル毎に設定可能 • 複数の端末でテストを⾏う場合 ü プロファイルを端末毎に作成 Ø 端末数が多い場合にプロファイルの作成が⼿間

    ü 全ての解像度を包含できるような解像度で作成 Ø 余⽩ができてしまい⾒栄えが悪い(がテスト⽤途なので気にしない) 事前設定 – キャンバス Android iOS
  111. © SEGA • 録画対象のウィンドウの設定が必要 • 名前で指定する ü iOSはQuickTimePlayerのウィンドウ名をそのまま ü Androidはscrcpyのオプションで指定

    事前設定 – シーン Android iOS
  112. © SEGA • シェル経由で終了することができない • 録画中にkillすると映像ファイルが壊れる • 「録画開始」、「録画終了」のキーボード ショートカットを設定し操作 事前設定

    – ショートカット Android iOS
  113. © SEGA • SoundFlowerというツールが必要 • OSとOBS両⽅でSoundFlowerの設定を⾏う 事前設定 – 録⾳ Android

    iOS
  114. © SEGA • --startrecording で起動後⾃動で録画開始する • --profile “name” でプロファイル指定可能 •

    その他のパラメータは公式ドキュメント参照 ü https://github.com/obsproject/obs-studio/wiki/Launch-Parameters OBSの起動時引数 Android iOS
  115. © SEGA export BUILD_ID=dontKillMe obs nohup open -a obs --args

    --profile $PROFILE_NAME & OBS – Jenkins例 Android iOS • 起動後自動で録画開始したい場合は --startrecording を入れる • 構築した環境ではテスト毎にOBS起動するコストが無駄なので起動と録 画開始は切り離している為にここでは –startrecording は入れていない
  116. © SEGA • OBSもWindowsに対応 • キーストロークを⾏うアプリでショートカット を操作する Windowsで録画 Android

  117. © SEGA • ロック中やRDPで運⽤しているPCでの録画は⼀ ⼯夫必要 ü Macはロック中でも録画可能 • 資料末尾にAppendixとして記載 Windowsで録画

  118. © SEGA テスト実⾏フェーズ Android 端末情報の取得 ミラーリングの準備 Androidビルド アプリを転送 録画用ソフトの起動 アプリを起動

    ミラーリング映像の録画開始 テストの実行 ミラーリング映像の録画停止 アプリを終了 録画ファイルのリネーム 録画用ソフトの終了 ミラーリングの停止 結果の解析と通知処理 準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
  119. © SEGA アプリケーションを転送・起動 USB アプリケー ションを起動 ミラーリング した映像の録 画開始 テストの実行

    ミラーリング した映像の録 画停止 録画ファイル のリネーム 1 2 3 4 5 Android
  120. © SEGA • 転送同様にadb.exeを使⽤する ü adb -s “デバイスID” shell am

    start “パッケージ名/アクティビティ名” アプリの起動 Android
  121. © SEGA adb -s $ANDROID_ID shell am start "$PACKAGE_NAME/$ACTIVITY_NAME" アプリの起動

    – Jenkins例 Android
  122. © SEGA 全体の流れ(iOS) iOS 端末情報の取得 ミラーリングの準備 録画用ソフトの起動 録画用ソフトの終了 ミラーリングの停止 結果の解析と通知処理

    準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ XCodeビルド アプリを転送・起動 ミラーリング映像の録画開始 テスト実行 ミラーリング映像の録画停止 アプリの終了 録画ファイルのリネーム
  123. © SEGA USB XCodeビルド アプリを転 送・起動 ミラーリン グした映像 の録画開始 テスト実行

    ミラーリン グした映像 の録画停止 アプリを終了 録画ファイル のリネーム 3 2 1 4 5 6 7 アプリケーションを転送・起動
  124. © SEGA • 転送/起動にはxcodebuildを⽤いる • xcodebuildでビルドと転送/起動を分ける ü build-for-testing : ビルドのみ実⾏

    ü test-without-building : 転送/起動を実⾏ アプリの転送/起動 iOS
  125. © SEGA • 連続実⾏すると失敗する ü 端末側の状態がリセットされない ü フルビルドで解消 test-without-building注意事項 iOS

  126. © SEGA アプリのビルド/転送/起動 端末情報の取得 ミラーリングの準備 録画用ソフトの起動 録画用ソフトの終了 ミラーリングの停止 結果の解析と通知処理 準備フェーズ

    テスト実行フェーズ(繰り返し) 終了フェーズ XCodeビルド アプリを転送・起動 ミラーリング映像の録画開始 テスト実行 ミラーリング映像の録画停止 アプリの終了 録画ファイルのリネーム 毎回フルビルドしたくない︕︕ iOS
  127. © SEGA • XCodeのキャッシュ内に⽣成された.appを削除 してbuild-for-testingすることで回避 ü .appの再⽣成だけなのでビルド時間は短い test-without-building連続実⾏ iOS

  128. © SEGA • キャッシュされた.appのパス ü /Library/Developer/Xcode/DerivedData/"xcodeproj名"-"ハッシュ値" /Build/Products/Debug-iphoneos/"プロダクト名".app • ハッシュ値の動的取得⽅法は不明 ü

    ⼀度決まると変わることはないので、環境構築時に⼀ 度⼿動でビルドして確認 test-without-building連続実⾏ iOS
  129. © SEGA • Xcodeのテストであるxctestが必要 • 何もせずに永久に待機し続けるxctestを実⾏する ことにより疑似的にアプリの起動を再現する test-without-buildingを使うには iOS

  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. © SEGA cd “Xcodeプロジェクト配置パス” # xcodebuildでアプリケーションを転送/起動する xcodebuild test-without-building -destination “platform=iOS,id=$IPHONE_UUID”

    -scheme “実⾏したいXcodeのScheme名" ARCHS=$ARCH_TYPE アプリの転送/起動 – Jenkins例 iOS
  132. © SEGA • 現在βのXcode13に追加される以下のオプション で再ビルド不要になりそう(未検証) ü -test-itreations <number> ü -retry-tests-on-failure

    ü -run-tests-until-failure 補⾜① - test-without-building iOS
  133. © SEGA • Xcode(GUI)からキーボードショートカット経由 で転送/起動する⼿もある ü Automator(AppleScript)から操作 • RPAツールの利⽤はあくまで最終⼿段 ü

    他の解決⽅法がある場合はそちらの採⽤がお勧め 補⾜② - Xcodeをキーボード操作 iOS
  134. © SEGA USB アプリを起動 ミラーリン グした映像 の録画開始 テストの実 行 ミラーリン

    グした映像 の録画停止 アプリを終了 録画ファイ ルのリネー ム 1 2 3 4 5 6 録画開始 Android
  135. © SEGA USB XCodeビルド アプリを転 送・起動 ミラーリン グした映像 の録画開始 テスト実行

    ミラーリン グした映像 の録画停止 アプリを終了 録画ファイル のリネーム 3 2 1 4 5 6 7 録画開始 iOS
  136. © SEGA • OBSの事前設定で決めたキーボードショート カットを使⽤する • 呼び出しはAppleScriptを⽤いる 録画開始 Android iOS

  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. © SEGA USB アプリを起動 ミラーリン グした映像 の録画開始 テストの実 行 ミラーリン

    グした映像 の録画停止 アプリを終了 録画ファイ ルのリネー ム 1 2 3 4 5 6 テストの実⾏ Android iOS
  139. © SEGA • テストフレームワーク次第ではこのタイミング で実⾏開始が必要 テストの実⾏ Android iOS 通信による操作 パラメータ送受信

    テストの実行
  140. © SEGA • 例︓今回構築した環境 テストの実⾏(例) Android iOS Jsonでテストしたい動作を指定 • テストケースに沿って操作を送信

    • 返信結果からテストの成否を判定 Jsonを解析して侵入型の テストを実行 指定した動作の結果を返信
  141. © SEGA • アプリの起動タイミングに仕込む ü 実⾏時の引数 Ø adbは引数オプション有り Ø xcodebuildはプリプロセッサマクロを活⽤

    ü テスト⽤コンフィグファイル Ø アプリ起動前に毎回端末に転送し直す等 テストの実⾏(⾮通信型) Android iOS
  142. © SEGA 録画停⽌ Android iOS USB アプリを起動 ミラーリン グした映像 の録画開始

    テストの実 行 ミラーリン グした映像 の録画停止 アプリを終了 録画ファイ ルのリネー ム 1 2 3 4 5 6
  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. © SEGA USB アプリを起動 ミラーリン グした映像 の録画開始 テストの実 行 ミラーリン

    グした映像 の録画停止 アプリを終了 録画ファイ ルのリネー ム 1 2 3 4 5 6 アプリの終了 Android iOS
  145. © SEGA • adb.exeで終了させる ü adb -s “デバイスID” shell am

    force-stop “パッケージ名” アプリの終了 Android
  146. © SEGA adb -s $ANDROID_ID shell am force-stop $PACKAGE_NAME アプリの終了

    – Jenkins例 Android
  147. © SEGA • xcodebuildをpkillする ü pkill “xcodebuild" アプリの終了 iOS

  148. © SEGA USB アプリを起動 ミラーリン グした映像 の録画開始 テストの実 行 ミラーリン

    グした映像 の録画停止 アプリを終了 録画ファイ ルのリネー ム 1 2 3 4 5 6 録画停⽌ Android iOS
  149. © SEGA • OBSのファイル名書式は⽇時等柔軟に指定可能 • しかし、起動時引数のようなものでテスト名を 動的に付与することはできない 録画ファイルのリネーム Android iOS

  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. © SEGA 具体的な環境構築の流れ 端末情報の取得 ミラーリングの準備 Androidビルド アプリを転送 録画用ソフトの起動 アプリを起動 ミラーリング映像の録画開始

    テストの実行 ミラーリング映像の録画停止 アプリを終了 録画ファイルのリネーム 録画用ソフトの終了 ミラーリングの停止 結果の解析と通知処理 準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
  152. © SEGA 録画⽤ソフトの終了 USB 録画用ソフトの 終了 端末映像のミ ラーリング停止 テスト結果の解 析と通知処理

    1 2 3 Android iOS
  153. © SEGA • pkillすればOK ü pkill "obs" OBSの終了 Android iOS

  154. © SEGA ミラーリング停⽌ USB 録画用ソフトの 終了 端末映像のミ ラーリング停止 テスト結果の解 析と通知処理

    1 2 3 Android iOS
  155. © SEGA • scrcpyはOBS同様pkillすればOK ü pkill "scrcpy“ • sndcpyはアンインストールする ü

    adb uninstall com.rom1v.sndcpy scrcpy/sndcpyの終了 Android
  156. © SEGA • 他のプロセス同様にpkillでOK ü pkill "QuickTime Player" Quick Time

    Playerの終了 iOS
  157. © SEGA 運⽤時に発⽣した問題とその解決⽅法の共有

  158. © SEGA • Android/iOS共にOSの⾃動アップデート通知が テスト中に割り込みで⼊る ü 操作不能になりテストが失敗する原因に • どちらのOSも⾃動アップデートは抑⽌できるの で設定を忘れずにしておく

    OSアップデート通知問題
  159. © SEGA • Automatorで記録したままの設定だとウェイト 値が不適切で動作が安定しないことがある ü Automator運⽤⽅針項で述べたように、複雑な操作 をAutomatorで実装する場合はAppleScriptで細かい 調整を⾏おう Automator操作が時々失敗する

  160. © SEGA • 録画映像に妙な余⽩が…… ノッチ対応アプリ録画映像の余⽩ ここ

  161. © SEGA • ノッチ対応している為にできた余⽩だった ü 逆説的に余⽩はノッチ対応の証拠なので確認に使える ノッチ対応アプリ録画映像の余⽩

  162. © SEGA ポップアップクローズ失敗 Android

  163. © SEGA 今後の展望

  164. © SEGA • 複数端末を並列でテストしたい ü 録画をどうするかが課題 ü OBSのキャンバスをうまく活⽤すれば……︖ • テスト中のパフォーマンスを取得したい

    ü ミラーリングの負荷の影響がどうしても出る 展望
  165. © SEGA 良い実機テストライフを︕︕

  166. © SEGA Appendix

  167. © SEGA Appendix Windowsで録画(ロック時の注意)

  168. © SEGA • 以下の実装ではロック画⾯そのものを録画して しまう ü Desktop Duplication API ü

    (最新の)WinRTのWindows.Graphics.Capture ロック時に録画できないケース
  169. © SEGA • アプリケーションの描画した結果画像を直接取 得する⽅法であれば録画可能 ü 例︓DXGIのPresentにフックを仕掛ける ⾃⼒で録画機能を実装する案

  170. © SEGA • OBSの録画も前者の録画できない⽅式に該当 • そこで、RDP等でロック解除して⾃動処理を実 ⾏する必要がある • しかしRDP接続に関しても録画は注意しないと いけない点がある

    OBSの場合
  171. © SEGA Appendix Windowsで録画(RDP接続時の注意)

  172. © SEGA • RDPで接続した状態であれば、ロック中でも録画 が可能 ü しかし常時RDP接続しておくわけにはいかない • テスト実⾏時にRDPが繋がっていなければ⾃動 的に接続を⾏う処理を挟む

    OBSとRDP接続を組み合わせて録画
  173. © SEGA • 例えば、DockerでUbuntuを動作させ、その中 でRemminaというOSSでRDP接続を⾏えるよう な環境を構築する • テスト開始時に録画を⾏いたいPCのセッション の有無を確認し、存在していない場合は前述し たUbuntuからRemmina経由でRDPにて接続を

    ⾏う テスト実⾏時にRDP接続
  174. © SEGA • RemminaによるRDP接続処理はUbuntuを Jenkinsのagentとして登録することにより実現 可能 • Ubuntu環境からRDP接続しているので画⾯ロッ クをしなくてもセキュリティが担保できる ü

    物理画⾯はログイン画⾯が表⽰される • PC再起動を考慮してUbuntuの起動やログイン処 理も⾃動化しておくのがお勧め 補⾜
  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. © SEGA • RDP切断時にtsconを⽤いてアクティブなセッ ションを切り替える⽅法も有り ü tscon <現在のセッションID> /dest:console •

    tsconを忘れると録画が失敗してしまうので運⽤ には注意が必要 ⾃動RDP接続対応が⾯倒な場合
  177. © SEGA Appendix iOSのIPアドレス取得(⾮同⼀LAN環境)

  178. © SEGA • パケットキャプチャ結果からIPアドレスをパー スする • rvictlを使ってMacOSから端末に仮想インター フェースをマウントし、これをtcpdumpするこ とでパケットキャプチャ可能 ü

    MacとiOS端末が⾮同⼀LAN内でも取得可能︕ パケットキャプチャ iOS
  179. © SEGA • 仮想インターフェースを作成するアプリを⽴ち 上げると rvictl が切断させることがある ü 例 :

    Quick Time Playerでミラーリングを⾏う • tcpdumpはsudoが必要 • 端末側からMacOSへ何らかのパケットを送信す る必要がある パケットキャプチャ注意事項 iOS
  180. © SEGA • ⾃作以外のアプリはshellから起動が難しい ü xcodebuild経由でないといけない ü QuickTimePlayerでミラーリングした画⾯をAutomator で操作してアプリ起動する⽅法は前述の切断問題がある為 にNG

    • ⾃前で以下の対応をするしかない ü 専⽤のアプリを作成する ü テストを⾏うアプリに仕込みを⼊れる 端末から通信を⾏う iOS
  181. © SEGA • UnityはDevelopmentフラグが有効の場合に ポート54997でデバッグ情報をマルチキャスト で投げる ü https://docs.unity3d.com/Manual/TroubleShootingIPhone.html • マルチキャストでフィルタするとrvictlが出して

    いるパケットまでキャッチしてしまうので注意 端末から通信を⾏う – Unityの例 iOS
  182. © SEGA • 投げられるパケット情報 端末から通信を⾏う – Unityの例 iOS IPが埋まっているので パースして活用

  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. © 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. © SEGA rvictlを終了(Pipeline) def rviEnd = "rvictl -x ${params.IPHONE_UUID}".execute() rviEnd.waitFor()

    Jenkins - Unity例 iOS 終了を忘れると仮想インターフェースが残ってしまうので注意
  186. © SEGA • iOS14からマルチキャストでの通信に強い制限が 掛かった ü Multicast Networking Entitlement申請が必要 ü

    更に端末側でのローカルネットワーク設定の許可も • Unityのデバッグパケットも上記対応をしないと キャプチャできない 補⾜ - iOS14からの注意事項 iOS
  187. © SEGA • マルチキャストを使わずに端末側からMacOS側 へ送信するような処理を⾃前で実装する必要が ある • HTTPでMacOCに向け通信を⾏うのが楽 ü MacOS側にサーバを⽤意しなくても送信パケットを

    キャプチャすればOK 補⾜ - iOS14からの注意事項 iOS
  188. © SEGA • VPN接続しているとrvictlでキャプチャできない ü VPNで⽣成された仮想インターフェース側にパケット が流れてしまう • 環境はVPN不要なネットワーク上に構築しよう ü

    scrcpyもQuickTimePlayerもミラーリング映像をマ ウスで操作できるので、いざという時でもVPN越しに 端末の操作を⾏うことが可能 補⾜ - VPN環境下の問題