SlideShare a Scribd company logo
Android/iOS 実機上での自動テストを
より楽に有意義にする為に
~端末管理・イメージ転送・動画記録等の周辺情報のノウハウ共有~
© SEGA
目次 - Android Android
準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
© SEGA
目次 -iOS
準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
iOS
XCodeビルド
アプリを転送・起動
ミラーリング映像の録画開始
テスト実行
ミラーリング映像の録画停止
アプリの終了
録画ファイルのリネーム
© SEGA
ゲームコンテンツ&サービス事業本部 技術本部 開発技術部
廣島 岳史
自己紹介
SEGA入社後
アーケード向けのライブラリ開発やツール作成などに従事
最近ではプランナー・デザイナに向けたGitHubEnterprise用のツール
の作成やUnity向け自動テスト支援ソリューションを開発しています
© SEGA
• 本講演内容の撮影、SNS投稿は OK
• 後日、CEDIL で資料を公開
• 講演中も質疑が可能です。
コメントに書き込んでください
• 講演後にZoomによる質疑応答を実施
• 資料に記載されている会社名、システム名、製品名、サービス名は各社の登録商標または
商標です
• Android ロボットは、Google が作成および提供している作品から複製または変更したもの
であり、
クリエイティブ・コモンズ表示 3.0 ライセンスに記載された条件に従って使用しています
© SEGA
• 自動テスト全体の流れ
• テストとその周辺環境に関して
• 具体的な環境構築の説明
• 運用時に発生した問題とその解決方法の共有
• 今後の展望
アジェンダ
© SEGA
自動テスト環境の構成
© SEGA
構築した自動テスト環境の構成図
USB
テストフレームワーク
通信による操作
パラメータ送受信
テストの実行
ネットワーク
© SEGA
本講演で取り上げる部分
© SEGA
使用しているソフトウェア
ミラーリング
(Android)
sndcpy
サウンドのミラーリング用のソフトのみ
ミラーリング
(iOS)
Quick Time Player
ミラーリング
(Android)
scrcpy
VLC
RPA Automator
録画 OBS Studio
© SEGA
ビルド&端末制御&録画担当(Mac)
アプリケーションのビルド
端末へのアプリケーションのインストール
端末情報の収集
テスト画面の録画
iOSアプリのビルドを行う事からMacを採用
Macのバージョンは Big Sur : 11.4
使用しているMacは Intel CPU
© SEGA
モバイル端末 (iOS / Android)
主な役割
アプリケーションの実行
テストフレームワークとの通信
ビルドマシンとはUSBを用いて接続
テストフレームワークとはWi-Fiで通信
© SEGA
全体の流れ(Android) Android
準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
© SEGA
全体の流れ(iOS)
準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
iOS
XCodeビルド
アプリを転送・起動
ミラーリング映像の録画開始
テスト実行
ミラーリング映像の録画停止
アプリの終了
録画ファイルのリネーム
© SEGA
これらに関してはこの講演では共有しません
• Android/iOS アプリのビルド
• テストの実行
• テスト結果の解析や通知
共有しない項目
© SEGA
準備フェーズ
USB
端末情報の
取得
ミラーリン
グの準備
ビルド
(Android)
アプリケー
ションを転送
(Android)
録画用ソフ
トの起動
1 2 3 4 5
© SEGA
テスト実行フェーズ(Android)
USB
アプリを起動
ミラーリン
グした映像
の録画開始
テストの実
行
ミラーリン
グした映像
の録画停止
アプリを終了
録画ファイ
ルのリネー
ム
1 2 3 4 5 6
© SEGA
テスト実行フェーズ(iOS)
USB
XCodeビルド
アプリを転
送・起動
ミラーリン
グした映像
の録画開始
テスト実行
ミラーリン
グした映像
の録画停止
アプリを終了
録画ファイル
のリネーム
3
2
1 4 5 6 7
© SEGA
終了フェーズ
USB
録画用ソフトの
終了
端末映像のミ
ラーリング停止
テスト結果の解
析と通知処理
1 2 3
© SEGA
 なぜ実機テストが必要か
 テストフレームワークについて
 オンプレ自前環境 vs クラウドサービス
 自動テストと録画の関係
本題に入る前に
© SEGA
• エミュレータ―を用いたテストだけでは不十分
• 端末でのみ発生する問題
なぜ実機でテストを行うのか
© SEGA
 そもそも関数が無かった
 ネイティブの関数の挙動が変わっていた
特定の端末・特定のバージョンで発生した
動かしてみるまで分からない
特定の端末で発生した不具合
© SEGA
テストフレームワークについて
© SEGA
• テストプロジェクトの作成
• テストスクリプトの作成
• テストスクリプトの実行
• テストレポートの出力
テストフレームワークの主な役割
© SEGA
NUnit
xunit
MSTest.TestFramework
Selenium
Appium
代表的なテストフレームワーク
ブラウザ
.NET
.NET
.NET
モバイル
© SEGA
• テストフレームワークとアプリケーションが
どのようにやり取りをするのかがポイント
テストフレームワークと環境構築
テストコード
© SEGA
• ゲームでは独自フレームワークの場合も多い
環境構築を視野に入れる事が重要
テストフレームワークを選定・実装する際
は、自動テスト環境の構築まで視野に入れて
選定を行う事をお勧めします
© SEGA
自動テスト環境の準備
© SEGA
クラウドのテストサービス
近年端末の種類も豊富なクラウドのテストサービ
スが多く登場
 AWS Device Farmなどが有名
 サービスを介して実機でテストを実行
 端末を用意する必要が無い
 端末の種類も豊富
テストコード
© SEGA
• 以前はオンプレしか選択肢は無かった
• プロジェクトの都合や予算で判断
オンプレミス vs クラウドサービス
© SEGA
• 並列実行に強み
• 端末を用意する必要が無い
• 端末の種類が豊富
クラウドサービスの特徴(メリット)
© SEGA
• お値段
• 使用可能なテストフレームワークに制限がかか
る事もある
• 他の人が端末を利用していて使えない事も
クラウドサービスの特徴(デメリット)
© SEGA
• お値段
• 自前のテストフレームワークの採用が可能
• テスト実行していない時は別の用途に転用可能
オンプレミス環境の特徴(メリット)
© SEGA
• 端末を用意する必要がある
• 構築・運用については全て自前
• 構築に関する知識が必要
当講演で解消可能!
オンプレミス環境の特徴(デメリット)
© SEGA
ハイブリッド(クラウド+オンプレミス)
USB
Azure pipelines self hosted agent
ビルドからデプロイまでをクラウドで実行
テストをオンプレミスで実行
Azure Pipelines self –hosted agent を使う
© SEGA
• お値段
• 独自形式のテストフレームワーク
• 導入するプロジェクトの秘匿性が高くテスト環
境を外に出すリスクが取れなかった
オンプレミスを採用しました
© SEGA
テスト実行中の録画について
© SEGA
• 再現性の低いバグの発生手順の確立
• 不具合の内容確認の容易性
実機テストでの録画の必要性
 自動テストレポートにテスト動画を含める
 BugTrackingSystemに動画付きで投稿する
効果的な使用例
© SEGA
• ミラーリングしたものを録画
• 端末で録画
• HDMI分配器を利用する
• カメラを用いて直接撮影する
録画手法について
© SEGA
ミラーリング
メリット
• タイトル毎に録画機能を実装しな
くて良い
• 録画ファイルの取り扱いが簡単
デメリット
• 複数端末同時録画が難しい
ミラーリングソフト
録画を行うデバイス
© SEGA
端末で録画
メリット
• 複数端末同時録画が可能
• 並列でテストが可能
デメリット
• タイトル毎に録画機能の実装が必要
• 端末毎にデバッグ
• 録画ファイルの取り扱いが複雑
画面を録画
録画データ転送
© SEGA
HDMI分配器を利用する
メリット
• 環境構築が容易
• 録画機能を実装しなくて良い
デメリット
• 端末との相性問題
• 端末数分の分配器用意する必
要がある
MHL変換アダプタ
HDMI分配器
録画を行うデバイス
© SEGA
カメラで録画
メリット
• 環境構築が比較的容易
デメリット
• 録画データの取り扱いが複雑
• 録画データのエンコーディン
グを自分で行う必要がある
• 複数端末分の機材が必要
© SEGA
採用理由
• タイトル毎に録画機能を実装しなくて良い
• データの取り扱いが容易な点
• 複数端末での実行が可能な点
が決め手になりました
ミラーリングを採用しました
© SEGA
• Andoroidでの録画方法
– MediaProjection APIで録画
– REQUEST_MEDIA_PROJECTIONなどの権限
が必要
• iOSでの録画方法
– ReplayKit について
端末での録画を行う場合(補足)
© SEGA
前半まとめ
テストフレームワーク 自動化を視野に選定・実装しましょう
自動化環境 クラウドサービスも多く存在します
録画
自動テストと録画は相性◎
積極的に利用しましょう
© SEGA
ゲームコンテンツ&サービス事業本部 技術本部 開発技術部
竹原 涼
自己紹介
【登壇歴】
CEDEC 2020 「技術同人作家になろう ~働き方改革時代におけるエン
ジニアのレベルアップの一例~」
Unite Tokyo 2019 「大量のアセットも怖くない!~HTTP/2による高
速な通信の実装例~」
CEDEC 2018、CEDEC 2016、CEDEC 2015 プロダクション関連のラ
ウンドテーブル
GDC2016 報告会 「GDC16にみる自動化技術とテストのトレンド」
© SEGA
具体的な環境構築の流れ
© SEGA
• 右上にプラットフォームを示すアイコンがあります
資料の見方 Android
iOS
© SEGA
準備フェーズ
準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
© SEGA
端末情報の
取得
ミラーリン
グの準備
ビルド
(Android)
アプリケー
ションを転送
(Android)
録画用ソフ
トの起動
端末情報の取得
USB
1 2 3 4 5
© SEGA
• 実機へのアプリ転送・実行には端末情報が必要
• Android
 デバイス名/デバイスID
• iOS
 デバイス名/UUID
• IPアドレスも必要な場合はここで取得しておくと楽
端末情報の取得
© SEGA
• adbコマンド結果をパースすることにより取得
• デバイス名/ID
 adb devices –l
• IPアドレス
 adb -s “デバイスID” shell ip addr show
端末情報の取得 Android
© 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
© 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/)
© SEGA
• xcrunコマンド結果をパースすることにより取得
• デバイス名/UUID
 xcrun instruments –s
• IPアドレス
 Bonjourの利用がお勧め
端末情報の取得 iOS
© SEGA
• 対応端末にデバイス名指定でアクセスできる
• デバイス名に.localを付けてアクセス
 デバイス名は準備フェーズで取得したものを流用
Bonjour iOS
© SEGA
• 以下のいずれかで実現
 自前でBonjourを実装しIPアドレス取得
 Bonjour対応アプリをMacOS上で起動しておく
Bonjourを使ったアクセス iOS
© SEGA
• 同一LAN内限定
• ActiveDirectoryと併用する場合に注意
 ローカルドメイン名に.localは使わない
Bonjour注意事項 iOS
© SEGA
• パケットキャプチャをすることで対応可能
 特殊な事例且つ長くなるので詳細はAppendixで
 Unityの場合の具体例が掲載されています
非同一LAN環境への対応 iOS
© 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
© SEGA
ミラーリングの準備
端末情報の
取得
ミラーリン
グの準備
ビルド
(Android)
アプリケー
ションを転送
(Android)
録画用ソフ
トの起動
USB
1 2 3 4 5
© SEGA
• 公式のミラーリングソフトは存在しない
 OSS やフリーのツールを利用するのが一般的
• 検証を行ったもの
 〇 scrcpy 採用!
 △ ApowerMirror
 ✖ Androidtool-mac, Vysor, Mobizen
ソフトウェアの選定 Android
© SEGA
• shell から操作可能
• オプションが豊富
• 端末にアプリケーションのインストールが不要
• USB経由でミラーリング可能
• ミラーリングされた画面からタッチ操作可能
scrcpyの特徴 Android
© SEGA
• 音声ミラーリング機能はない
• 録画機能は可能だが無圧縮
• コマンドで起動後、処理が返ってこない
scrcpy注意事項 Android
© SEGA
• 以下の3通りのいずれかで対応可能
1. ProcessTreeKillerから逃れる (お勧め!)
2. Pipelineで並列化する
3. AppleScriptを使ってJenkinsから切り離す
scrcpyをJenkinsで使う場合 Android
© SEGA
• Jenkinsはジョブ中に起動したプロセスをその
ジョブ終了時に強制終了する
 https://wiki.jenkins.io/display/JENKINS/ProcessTreeKiller
• nohup & を使ってもジョブを抜ける際にアウト
ProcessTreeKiller補足 Android
© SEGA
• shellの場合は環境変数 BUILD_ID に
dontKillMe プロセスパス(名) を入れて回避
• shell設定例
 export BUILD_ID=dontKillMe scrcpy
nohup scrcpy <options> &
ProcessTreeKiller補足 Android
© SEGA
• PipelineはJENKINS_NODE_COOKIEに設定
• Pipeline実行例
 steps {
sh '''
export JENKINS_NODE_COOKIE=dontkillMe
nohup scrcpy <options> &
'''
}
ProcessTreeKiller補足 Android
© SEGA
• sndcpyを使う
 scrcpyと一緒に使う為に作成されたOSS
音声ミラーリングしたい Android
© SEGA
• Android 10から使用可能
 内部的にAudioPlaybackCapture APIを使用
• 端末へのアプリケーションインストールが必要
sndcpy注意事項 Android
© SEGA
sndcpyというスクリプト内で以下が実行される
1. sndcpyを端末へインストール
2. 端末上でsndcpy起動
3. 端末側でポップアップが出る
4. ポップアップを閉じる (手動で「今すぐ開始」を押す)
5. PC側でVLCを起動する
音声ミラーリングまでの流れ Android
ここを自動化したい
© SEGA
• ポップアップはAndroid側が出しているので抑制
できない
• 最終手段のAutomatorを利用
 MacOSに標準搭載されているというRPAツール
sndcpyカスタマイズ Android
© SEGA
• ユーザ操作を記録・再現するRPAツール
 アプリケーションとして保存できる
 内部的にはAppleScript(後述)に落とし込まれる
• レイアウトの変更には弱い
 なるべく座標指定しないような実装にはなっている
Automator Android
© SEGA
• Apple 独自のスクリプト言語
• shellから呼び出し可能
 shellの先頭に #!/usr/bin/env osascript を付ける
• キーボードやマウス等の操作が可能
AppleScript Android
© SEGA
• 資料が少ない
 オンラインの公式ドキュメントは情報が古いことも
• AppleScriptメニュー内にある用語説明がお勧め
AppleScript注意事項 Android
© SEGA
• 画面ロック中は操作できないものがある
 キーボード、マウス操作
AppleScript注意事項 Android
© SEGA
• 簡単な操作ならAppleScript単体で実装する
• 複雑な操作はAutomatorで実装する
 AppleScriptに変換して細部を修正可能
Automator運用方針 Android
© SEGA
ポップアップクローズの自動化 Android
© SEGA
Automatorで記憶された操作 Android
© SEGA
Automatorの修正 Android
ドラッグ&ドロップ
項目の内容がコピーされる
© SEGA
Automatorの修正 Android
ドラッグ&ドロップ
コピーなので保存してもこの中の項目には反映されない
これは1個目のコピー(編集はコピーしかできない)
これは2個目のコピー
© SEGA
Automatorの修正 Android
イベントをここから全部消せる
© SEGA
Automatorの修正 Android
© SEGA
• ポップアップを閉じたことを確認してから次の
処理に進みたい
 openコマンドでは終了を待てない
• Automatorアプリ終了を待つAppleScriptを作成
Automatorアプリの終了を待つ Android
© 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
引数で受け取ったコマンドを実行
起動したプロセスが存在する限り待つ
© SEGA
1. sndcpyを端末へインストール
2. sndcpy起動
3. 端末側でポップアップが出る
4. ポップアップを閉じる
5. PC側でVLCを起動する
音声ミラーリングまでの流れ Android
sndcpyを分割して自前のAutomatorの処理を挟む
strat_vlc.sh
sndcpy
Automator処理
© 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
© 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
© 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の端末をミラーリング
© SEGA
# sndcpyインストールと起動
./sndcpy
# ポップアップの抑制
./doandwait_process.sh "exec open -a SupSndcpyPopup" "SupSndcpyPopup"
# VLCの起動
export BUILD_ID=dontKillMe start_vlc
nohup ./start_vlc &
sndcpy - Jenkins例 Android
© SEGA
• scrcpy/sndcpyはWindowsにも対応
 sndcpy.batを使う等細かい差異はあるが基本同じ対
応で自動化可能
• ポップアップの抑制にはWindows対応のRPA
ツールで代用を
Windowsでミラーリング Android
© SEGA
• Quick Time Playerでミラーリングが可能
 MacOSに標準インストール
• Quick Time Player以外の候補は見つからず
• 自動化についてはハマり所がいくつかある
ソフトウェアの選定 iOS
© SEGA
• Quick Time Playerで録画することは可能
 ただしエンコーディング無し
Quick Time Playerでの録画 iOS
© SEGA
• ミラーリング映像から操作が可能
• shell経由での細かい実行をサポートしていない
• 最終的に再びAutomatorに頼ることに
Quick Time Playerの自動化 iOS
© SEGA
Automatorでの起動 iOS
© SEGA
export BUILD_ID=dontKillMe start_iphone_mirroring
nohup open -a start_iphone_mirroring &
Quick Time Player – Jenkins例 iOS
© SEGA
• 複数のiPhoneが接続されている場合、Android
同様に端末を指定したい
複数デバイス対応 iOS
© SEGA
• Automatorアプリは起動時引数に制限がある
 ファイルパスしか渡せない
• 環境変数にデバイス名を保存しておき、それを
Automator内のAppleScriptで読み込む
複数デバイス対応 - Automator iOS
© 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 で読める
© SEGA
複数デバイス対応- Jenkins例 iOS
export BUILD_ID=dontKillMe start_iphone_mirroring
export DeviceName=“devtech-iphone“
nohup open -a start_iphone_mirroring &
Jenkins側は環境変数設定を挟むだけでOK
“あいふぉん”のような日本語はアウトなので注意
© SEGA
録画用ソフトの起動
端末情報の
取得
ミラーリン
グの準備
ビルド
(Android)
アプリケー
ションを転送
(Android)
録画用ソフ
トの起動
USB
1 2 3 4 5
Android
© SEGA
テスト実行フェーズ Android
端末情報の取得
ミラーリングの準備
Androidビルド
アプリを転送
録画用ソフトの起動
アプリを起動
ミラーリング映像の録画開始
テストの実行
ミラーリング映像の録画停止
アプリを終了
録画ファイルのリネーム
準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
ビルド・転送は準備フェーズに実行
起動のみテスト毎に実行することで効率アップ
© SEGA
• adb.exeを使用する
 adb -s “デバイスID” install ”アプリケーションイメージのパス”
アプリの転送 Android
© SEGA
adb -s $ANDROID_ID install $APPLICATION_PATH
アプリの転送 – Jenkins例 Android
© SEGA
録画用ソフトの起動
端末情報の
取得
ミラーリン
グの準備
ビルド
(Android)
アプリケー
ションを転送
(Android)
録画用ソフ
トの起動
USB
1 2 3 4 5
© SEGA
• 検証を行ったもの
 〇 OBS Studio 採用!
 △ scrcpy/Quick Time Player
ソフトウェアの選定 Android iOS
© SEGA
• シェルから起動オプションが指定可能
• ほぼ全ての操作のキーボードショートカット有
• websocketによる操作も可能
• 録画と同時にエンコーディング可能
• 配信でよく利用されており更新が非常に活発
OBS Studioの特徴 Android iOS
© SEGA
• OBSはプロファイル単位で種々の設定が可能
 起動時の引数でこのプロファイルを指定できる
• 自動化用にプロファイルを作成しておく
 プロファイル名にIDやデバイス名を使うと楽
事前設定 - プロファイル Android iOS
© SEGA
• プロファイル毎に設定可能
• 複数の端末でテストを行う場合
 プロファイルを端末毎に作成
 端末数が多い場合にプロファイルの作成が手間
 全ての解像度を包含できるような解像度で作成
 余白ができてしまい見栄えが悪い(がテスト用途なので気にしない)
事前設定 – キャンバス Android iOS
© SEGA
• 録画対象のウィンドウの設定が必要
• 名前で指定する
 iOSはQuickTimePlayerのウィンドウ名をそのまま
 Androidはscrcpyのオプションで指定
事前設定 – シーン Android iOS
© SEGA
• シェル経由で終了することができない
• 録画中にkillすると映像ファイルが壊れる
• 「録画開始」、「録画終了」のキーボード
ショートカットを設定し操作
事前設定 – ショートカット Android iOS
© SEGA
• SoundFlowerというツールが必要
• OSとOBS両方でSoundFlowerの設定を行う
事前設定 – 録音 Android iOS
© SEGA
• --startrecording で起動後自動で録画開始する
• --profile “name” でプロファイル指定可能
• その他のパラメータは公式ドキュメント参照
 https://github.com/obsproject/obs-studio/wiki/Launch-Parameters
OBSの起動時引数 Android iOS
© SEGA
export BUILD_ID=dontKillMe obs
nohup open -a obs --args --profile $PROFILE_NAME &
OBS – Jenkins例 Android iOS
• 起動後自動で録画開始したい場合は --startrecording を入れる
• 構築した環境ではテスト毎にOBS起動するコストが無駄なので起動と録
画開始は切り離している為にここでは –startrecording は入れていない
© SEGA
• OBSもWindowsに対応
• キーストロークを行うアプリでショートカット
を操作する
Windowsで録画 Android
© SEGA
• ロック中やRDPで運用しているPCでの録画は一
工夫必要
 Macはロック中でも録画可能
• 資料末尾にAppendixとして記載
Windowsで録画
© SEGA
テスト実行フェーズ Android
端末情報の取得
ミラーリングの準備
Androidビルド
アプリを転送
録画用ソフトの起動
アプリを起動
ミラーリング映像の録画開始
テストの実行
ミラーリング映像の録画停止
アプリを終了
録画ファイルのリネーム
録画用ソフトの終了
ミラーリングの停止
結果の解析と通知処理
準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
© SEGA
アプリケーションを転送・起動
USB
アプリケー
ションを起動
ミラーリング
した映像の録
画開始
テストの実行
ミラーリング
した映像の録
画停止
録画ファイル
のリネーム
1 2 3 4 5
Android
© SEGA
• 転送同様にadb.exeを使用する
 adb -s “デバイスID” shell am start “パッケージ名/アクティビティ名”
アプリの起動 Android
© SEGA
adb -s $ANDROID_ID shell am start "$PACKAGE_NAME/$ACTIVITY_NAME"
アプリの起動 – Jenkins例 Android
© SEGA
全体の流れ(iOS) iOS
端末情報の取得
ミラーリングの準備
録画用ソフトの起動
録画用ソフトの終了
ミラーリングの停止
結果の解析と通知処理
準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
XCodeビルド
アプリを転送・起動
ミラーリング映像の録画開始
テスト実行
ミラーリング映像の録画停止
アプリの終了
録画ファイルのリネーム
© SEGA
USB
XCodeビルド
アプリを転
送・起動
ミラーリン
グした映像
の録画開始
テスト実行
ミラーリン
グした映像
の録画停止
アプリを終了
録画ファイル
のリネーム
3
2
1 4 5 6 7
アプリケーションを転送・起動
© SEGA
• 転送/起動にはxcodebuildを用いる
• xcodebuildでビルドと転送/起動を分ける
 build-for-testing : ビルドのみ実行
 test-without-building : 転送/起動を実行
アプリの転送/起動 iOS
© SEGA
• 連続実行すると失敗する
 端末側の状態がリセットされない
 フルビルドで解消
test-without-building注意事項 iOS
© SEGA
アプリのビルド/転送/起動
端末情報の取得
ミラーリングの準備
録画用ソフトの起動
録画用ソフトの終了
ミラーリングの停止
結果の解析と通知処理
準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
XCodeビルド
アプリを転送・起動
ミラーリング映像の録画開始
テスト実行
ミラーリング映像の録画停止
アプリの終了
録画ファイルのリネーム
毎回フルビルドしたくない!!
iOS
© SEGA
• XCodeのキャッシュ内に生成された.appを削除
してbuild-for-testingすることで回避
 .appの再生成だけなのでビルド時間は短い
test-without-building連続実行 iOS
© SEGA
• キャッシュされた.appのパス
 /Library/Developer/Xcode/DerivedData/"xcodeproj名"-"ハッシュ値"
/Build/Products/Debug-iphoneos/"プロダクト名".app
• ハッシュ値の動的取得方法は不明
 一度決まると変わることはないので、環境構築時に一
度手動でビルドして確認
test-without-building連続実行 iOS
© SEGA
• Xcodeのテストであるxctestが必要
• 何もせずに永久に待機し続けるxctestを実行する
ことにより疑似的にアプリの起動を再現する
test-without-buildingを使うには iOS
© 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
© SEGA
cd “Xcodeプロジェクト配置パス”
# xcodebuildでアプリケーションを転送/起動する
xcodebuild test-without-building -destination “platform=iOS,id=$IPHONE_UUID” -scheme
“実行したいXcodeのScheme名" ARCHS=$ARCH_TYPE
アプリの転送/起動 – Jenkins例 iOS
© SEGA
• 現在βのXcode13に追加される以下のオプション
で再ビルド不要になりそう(未検証)
 -test-itreations <number>
 -retry-tests-on-failure
 -run-tests-until-failure
補足① - test-without-building iOS
© SEGA
• Xcode(GUI)からキーボードショートカット経由
で転送/起動する手もある
 Automator(AppleScript)から操作
• RPAツールの利用はあくまで最終手段
 他の解決方法がある場合はそちらの採用がお勧め
補足② - Xcodeをキーボード操作 iOS
© SEGA
USB
アプリを起動
ミラーリン
グした映像
の録画開始
テストの実
行
ミラーリン
グした映像
の録画停止
アプリを終了
録画ファイ
ルのリネー
ム
1 2 3 4 5 6
録画開始 Android
© SEGA
USB
XCodeビルド
アプリを転
送・起動
ミラーリン
グした映像
の録画開始
テスト実行
ミラーリン
グした映像
の録画停止
アプリを終了
録画ファイル
のリネーム
3
2
1 4 5 6 7
録画開始 iOS
© SEGA
• OBSの事前設定で決めたキーボードショート
カットを使用する
• 呼び出しはAppleScriptを用いる
録画開始 Android iOS
© 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
© SEGA
USB
アプリを起動
ミラーリン
グした映像
の録画開始
テストの実
行
ミラーリン
グした映像
の録画停止
アプリを終了
録画ファイ
ルのリネー
ム
1 2 3 4 5 6
テストの実行 Android iOS
© SEGA
• テストフレームワーク次第ではこのタイミング
で実行開始が必要
テストの実行 Android iOS
通信による操作
パラメータ送受信
テストの実行
© SEGA
• 例:今回構築した環境
テストの実行(例) Android iOS
Jsonでテストしたい動作を指定
• テストケースに沿って操作を送信
• 返信結果からテストの成否を判定
Jsonを解析して侵入型の
テストを実行
指定した動作の結果を返信
© SEGA
• アプリの起動タイミングに仕込む
 実行時の引数
 adbは引数オプション有り
 xcodebuildはプリプロセッサマクロを活用
 テスト用コンフィグファイル
 アプリ起動前に毎回端末に転送し直す等
テストの実行(非通信型) Android iOS
© SEGA
録画停止 Android iOS
USB
アプリを起動
ミラーリン
グした映像
の録画開始
テストの実
行
ミラーリン
グした映像
の録画停止
アプリを終了
録画ファイ
ルのリネー
ム
1 2 3 4 5 6
© 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
© SEGA
USB
アプリを起動
ミラーリン
グした映像
の録画開始
テストの実
行
ミラーリン
グした映像
の録画停止
アプリを終了
録画ファイ
ルのリネー
ム
1 2 3 4 5 6
アプリの終了 Android iOS
© SEGA
• adb.exeで終了させる
 adb -s “デバイスID” shell am force-stop “パッケージ名”
アプリの終了 Android
© SEGA
adb -s $ANDROID_ID shell am force-stop $PACKAGE_NAME
アプリの終了 – Jenkins例 Android
© SEGA
• xcodebuildをpkillする
 pkill “xcodebuild"
アプリの終了 iOS
© SEGA
USB
アプリを起動
ミラーリン
グした映像
の録画開始
テストの実
行
ミラーリン
グした映像
の録画停止
アプリを終了
録画ファイ
ルのリネー
ム
1 2 3 4 5 6
録画停止 Android iOS
© SEGA
• OBSのファイル名書式は日時等柔軟に指定可能
• しかし、起動時引数のようなものでテスト名を
動的に付与することはできない
録画ファイルのリネーム Android iOS
© SEGA
• テスト終了毎にファイルをテスト名を付与した
ものにリネームしてあげると結果確認時に分か
り易い
• shell例(移動するついでにリネーム)
 mv -f $OBS_OUTPUT_PATH/*.mp4 $STORAGE_PATH/$TEST_NAME_`date "+%Y%m%d%H%M"`.mp4
録画ファイルのリネーム Android iOS
※CatchExceptionTest_202104021241.mp4のような名前で保存される
© SEGA
具体的な環境構築の流れ
端末情報の取得
ミラーリングの準備
Androidビルド
アプリを転送
録画用ソフトの起動
アプリを起動
ミラーリング映像の録画開始
テストの実行
ミラーリング映像の録画停止
アプリを終了
録画ファイルのリネーム
録画用ソフトの終了
ミラーリングの停止
結果の解析と通知処理
準備フェーズ テスト実行フェーズ(繰り返し) 終了フェーズ
© SEGA
録画用ソフトの終了
USB
録画用ソフトの
終了
端末映像のミ
ラーリング停止
テスト結果の解
析と通知処理
1 2 3
Android iOS
© SEGA
• pkillすればOK
 pkill "obs"
OBSの終了 Android iOS
© SEGA
ミラーリング停止
USB
録画用ソフトの
終了
端末映像のミ
ラーリング停止
テスト結果の解
析と通知処理
1 2 3
Android iOS
© SEGA
• scrcpyはOBS同様pkillすればOK
 pkill "scrcpy“
• sndcpyはアンインストールする
 adb uninstall com.rom1v.sndcpy
scrcpy/sndcpyの終了 Android
© SEGA
• 他のプロセス同様にpkillでOK
 pkill "QuickTime Player"
Quick Time Playerの終了 iOS
© SEGA
運用時に発生した問題とその解決方法の共有
© SEGA
• Android/iOS共にOSの自動アップデート通知が
テスト中に割り込みで入る
 操作不能になりテストが失敗する原因に
• どちらのOSも自動アップデートは抑止できるの
で設定を忘れずにしておく
OSアップデート通知問題
© SEGA
• Automatorで記録したままの設定だとウェイト
値が不適切で動作が安定しないことがある
 Automator運用方針項で述べたように、複雑な操作
をAutomatorで実装する場合はAppleScriptで細かい
調整を行おう
Automator操作が時々失敗する
© SEGA
• 録画映像に妙な余白が……
ノッチ対応アプリ録画映像の余白
ここ
© SEGA
• ノッチ対応している為にできた余白だった
 逆説的に余白はノッチ対応の証拠なので確認に使える
ノッチ対応アプリ録画映像の余白
© SEGA
ポップアップクローズ失敗 Android
© SEGA
今後の展望
© SEGA
• 複数端末を並列でテストしたい
 録画をどうするかが課題
 OBSのキャンバスをうまく活用すれば……?
• テスト中のパフォーマンスを取得したい
 ミラーリングの負荷の影響がどうしても出る
展望
© SEGA
良い実機テストライフを!!
© SEGA
Appendix
© SEGA
Appendix
Windowsで録画(ロック時の注意)
© SEGA
• 以下の実装ではロック画面そのものを録画して
しまう
 Desktop Duplication API
 (最新の)WinRTのWindows.Graphics.Capture
ロック時に録画できないケース
© SEGA
• アプリケーションの描画した結果画像を直接取
得する方法であれば録画可能
 例:DXGIのPresentにフックを仕掛ける
自力で録画機能を実装する案
© SEGA
• OBSの録画も前者の録画できない方式に該当
• そこで、RDP等でロック解除して自動処理を実
行する必要がある
• しかしRDP接続に関しても録画は注意しないと
いけない点がある
OBSの場合
© SEGA
Appendix
Windowsで録画(RDP接続時の注意)
© SEGA
• RDPで接続した状態であれば、ロック中でも録画
が可能
 しかし常時RDP接続しておくわけにはいかない
• テスト実行時にRDPが繋がっていなければ自動
的に接続を行う処理を挟む
OBSとRDP接続を組み合わせて録画
© SEGA
• 例えば、DockerでUbuntuを動作させ、その中
でRemminaというOSSでRDP接続を行えるよう
な環境を構築する
• テスト開始時に録画を行いたいPCのセッション
の有無を確認し、存在していない場合は前述し
たUbuntuからRemmina経由でRDPにて接続を
行う
テスト実行時にRDP接続
© SEGA
• RemminaによるRDP接続処理はUbuntuを
Jenkinsのagentとして登録することにより実現
可能
• Ubuntu環境からRDP接続しているので画面ロッ
クをしなくてもセキュリティが担保できる
 物理画面はログイン画面が表示される
• PC再起動を考慮してUbuntuの起動やログイン処
理も自動化しておくのがお勧め
補足
© 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%
セッションの確認実装例
© SEGA
• RDP切断時にtsconを用いてアクティブなセッ
ションを切り替える方法も有り
 tscon <現在のセッションID> /dest:console
• tsconを忘れると録画が失敗してしまうので運用
には注意が必要
自動RDP接続対応が面倒な場合
© SEGA
Appendix
iOSのIPアドレス取得(非同一LAN環境)
© SEGA
• パケットキャプチャ結果からIPアドレスをパー
スする
• rvictlを使ってMacOSから端末に仮想インター
フェースをマウントし、これをtcpdumpするこ
とでパケットキャプチャ可能
 MacとiOS端末が非同一LAN内でも取得可能!
パケットキャプチャ iOS
© SEGA
• 仮想インターフェースを作成するアプリを立ち
上げると rvictl が切断させることがある
 例 : Quick Time Playerでミラーリングを行う
• tcpdumpはsudoが必要
• 端末側からMacOSへ何らかのパケットを送信す
る必要がある
パケットキャプチャ注意事項 iOS
© SEGA
• 自作以外のアプリはshellから起動が難しい
 xcodebuild経由でないといけない
 QuickTimePlayerでミラーリングした画面をAutomator
で操作してアプリ起動する方法は前述の切断問題がある為
にNG
• 自前で以下の対応をするしかない
 専用のアプリを作成する
 テストを行うアプリに仕込みを入れる
端末から通信を行う iOS
© SEGA
• UnityはDevelopmentフラグが有効の場合に
ポート54997でデバッグ情報をマルチキャスト
で投げる
 https://docs.unity3d.com/Manual/TroubleShootingIPhone.html
• マルチキャストでフィルタするとrvictlが出して
いるパケットまでキャッチしてしまうので注意
端末から通信を行う – Unityの例 iOS
© SEGA
• 投げられるパケット情報
端末から通信を行う – Unityの例 iOS
IPが埋まっているので
パースして活用
© 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
© 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
前ページで作成した仮想インターフェース名
© SEGA
rvictlを終了(Pipeline)
def rviEnd = "rvictl -x ${params.IPHONE_UUID}".execute()
rviEnd.waitFor()
Jenkins - Unity例 iOS
終了を忘れると仮想インターフェースが残ってしまうので注意
© SEGA
• iOS14からマルチキャストでの通信に強い制限が
掛かった
 Multicast Networking Entitlement申請が必要
 更に端末側でのローカルネットワーク設定の許可も
• Unityのデバッグパケットも上記対応をしないと
キャプチャできない
補足 - iOS14からの注意事項 iOS
© SEGA
• マルチキャストを使わずに端末側からMacOS側
へ送信するような処理を自前で実装する必要が
ある
• HTTPでMacOCに向け通信を行うのが楽
 MacOS側にサーバを用意しなくても送信パケットを
キャプチャすればOK
補足 - iOS14からの注意事項 iOS
© SEGA
• VPN接続しているとrvictlでキャプチャできない
 VPNで生成された仮想インターフェース側にパケット
が流れてしまう
• 環境はVPN不要なネットワーク上に構築しよう
 scrcpyもQuickTimePlayerもミラーリング映像をマ
ウスで操作できるので、いざという時でもVPN越しに
端末の操作を行うことが可能
補足 - VPN環境下の問題

More Related Content

PDF
「龍が如く7 光と闇の行方」の自動テスト活用事例とテスト自動化チーム(仮)による若手育成の取り組みについて
PDF
Appium 2.0 ではじめるモバイルアプリテスト
PDF
ゴリラテスト モバイルゲームのUIを自動的に検出・操作する モンキーテスト
PPTX
60分でわかった気になるISO29119 #wacate
PDF
【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう
PPTX
アジャイルメトリクス実践ガイド
PDF
MagicOnion~C#でゲームサーバを開発しよう~
PDF
ユーザーインタビューするときは、どうやらゾンビのおでましさ
「龍が如く7 光と闇の行方」の自動テスト活用事例とテスト自動化チーム(仮)による若手育成の取り組みについて
Appium 2.0 ではじめるモバイルアプリテスト
ゴリラテスト モバイルゲームのUIを自動的に検出・操作する モンキーテスト
60分でわかった気になるISO29119 #wacate
【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう
アジャイルメトリクス実践ガイド
MagicOnion~C#でゲームサーバを開発しよう~
ユーザーインタビューするときは、どうやらゾンビのおでましさ

What's hot (20)

PDF
AppiumのWebViewアプリテストの仕組みとハマりどころ
PDF
2020年8月_HoloLens 2 アプリ開発入門
PPTX
テストコードの DRY と DAMP
PDF
オブジェクト指向エクササイズのススメ
PDF
View Customize Pluginで出来ること
PDF
ドメイン駆動設計をゲーム開発に活かす
PDF
Dockerfile を書くためのベストプラクティス解説編
PPTX
MVPパターンによる設計アプローチ「あなたのアプリ報連相できてますか」
PPTX
大規模ゲーム開発における build 高速化と安定化
PDF
テストを分類してみよう!
PDF
[UE4]自動テストでもっと楽したい!
PDF
テスト分析・設計を体感しよう ~マインドマップを活用してテスト観点を発想しよう
PDF
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
PDF
The Usage and Patterns of MagicOnion
PPTX
世界一わかりやすいClean Architecture
PDF
Redmine にいろいろ埋め込んでみた
PPTX
DockerコンテナでGitを使う
PDF
ドメインオブジェクトの見つけ方・作り方・育て方
PPTX
なぜなにリアルタイムレンダリング
PDF
テストの極みを目指して ~さあ、理想に近づくための一歩を踏み出そう!~
AppiumのWebViewアプリテストの仕組みとハマりどころ
2020年8月_HoloLens 2 アプリ開発入門
テストコードの DRY と DAMP
オブジェクト指向エクササイズのススメ
View Customize Pluginで出来ること
ドメイン駆動設計をゲーム開発に活かす
Dockerfile を書くためのベストプラクティス解説編
MVPパターンによる設計アプローチ「あなたのアプリ報連相できてますか」
大規模ゲーム開発における build 高速化と安定化
テストを分類してみよう!
[UE4]自動テストでもっと楽したい!
テスト分析・設計を体感しよう ~マインドマップを活用してテスト観点を発想しよう
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
The Usage and Patterns of MagicOnion
世界一わかりやすいClean Architecture
Redmine にいろいろ埋め込んでみた
DockerコンテナでGitを使う
ドメインオブジェクトの見つけ方・作り方・育て方
なぜなにリアルタイムレンダリング
テストの極みを目指して ~さあ、理想に近づくための一歩を踏み出そう!~
Ad

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

PDF
Gamedevenvstudy1
PDF
GDC2018報告会AI分野
PDF
ゲームの自動テストを 作ってみた
PPTX
Game Development and Automation @ Agile Sapporo 2018 #1
PDF
剣と魔法のログレス いにしえの女神 〜スマホ時代の MMORPG を支える技術
PDF
大規模JavaScript開発
PDF
ゲーム開発環境の自動化
PPTX
クリエイター魂を刺激する!シンラが提案する「ゲームの超進化」ロードマップ
PDF
0621 ndk game
PDF
【Unite Tokyo 2019】「禍つヴァールハイト」Timelineだから可能だった!モバイルに最適化されたリアルタイム3D演出!
PDF
【Unite Tokyo 2019】「禍つヴァールハイト」Timelineだから可能だった!モバイルに最適化されたリアルタイム3D演出!
PPTX
Unity * スマートフォン開発で学んだこと
PDF
次世代QAとAI 〜ゲーム開発におけるAI活用に正しく向き合うために〜
PDF
CEDEC 2013 - 徹底的にチューンしたハイブリッドアプリ「D.O.T. Defender of Texel」の制作
PDF
テスト自動化クロニクル (JaSST 東海 2016)
PDF
Unityファンへ贈る! Unite12 & gamescom 2012 視察報告
PDF
Unityで作るiOSゲームアプリ
PDF
SGT2013 技術トークス「アジャイルテスティング」
PPTX
メガ Unity ユーザーミートアップ 2012
PPTX
Device Farm を使ったスマホアプリの自動テスト
Gamedevenvstudy1
GDC2018報告会AI分野
ゲームの自動テストを 作ってみた
Game Development and Automation @ Agile Sapporo 2018 #1
剣と魔法のログレス いにしえの女神 〜スマホ時代の MMORPG を支える技術
大規模JavaScript開発
ゲーム開発環境の自動化
クリエイター魂を刺激する!シンラが提案する「ゲームの超進化」ロードマップ
0621 ndk game
【Unite Tokyo 2019】「禍つヴァールハイト」Timelineだから可能だった!モバイルに最適化されたリアルタイム3D演出!
【Unite Tokyo 2019】「禍つヴァールハイト」Timelineだから可能だった!モバイルに最適化されたリアルタイム3D演出!
Unity * スマートフォン開発で学んだこと
次世代QAとAI 〜ゲーム開発におけるAI活用に正しく向き合うために〜
CEDEC 2013 - 徹底的にチューンしたハイブリッドアプリ「D.O.T. Defender of Texel」の制作
テスト自動化クロニクル (JaSST 東海 2016)
Unityファンへ贈る! Unite12 & gamescom 2012 視察報告
Unityで作るiOSゲームアプリ
SGT2013 技術トークス「アジャイルテスティング」
メガ Unity ユーザーミートアップ 2012
Device Farm を使ったスマホアプリの自動テスト
Ad

More from SEGADevTech (7)

PDF
CEDEC 2025 『ゲームにおけるリアルタイム通信への QUIC導入事例の紹介』
PDF
「龍が如く」も「スーパーモンキーボール」も自動化!クオリティエンジニアリングチームによるマルチゲームエンジン対応で進化した「龍が如くスタジオ」のテスト自動...
PDF
開発もQAも自動テスト!「LOST JUDGMENT:裁かれざる記憶」のQAテスター参加で進化した「テスト自動化チーム(仮)」の取り組みについて
PDF
CEDEC2021 プランナーもハックしよう 業務効率化、ローコード開発とテクニカルプランナー
PPTX
CEDEC2021 ダウンロード時間を大幅減!~大量のアセットをさばく高速な実装と運用事例の共有~
PDF
基礎線形代数講座
PDF
Jenkinsの構成・運用パターン
CEDEC 2025 『ゲームにおけるリアルタイム通信への QUIC導入事例の紹介』
「龍が如く」も「スーパーモンキーボール」も自動化!クオリティエンジニアリングチームによるマルチゲームエンジン対応で進化した「龍が如くスタジオ」のテスト自動...
開発もQAも自動テスト!「LOST JUDGMENT:裁かれざる記憶」のQAテスター参加で進化した「テスト自動化チーム(仮)」の取り組みについて
CEDEC2021 プランナーもハックしよう 業務効率化、ローコード開発とテクニカルプランナー
CEDEC2021 ダウンロード時間を大幅減!~大量のアセットをさばく高速な実装と運用事例の共有~
基礎線形代数講座
Jenkinsの構成・運用パターン

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

Editor's Notes

  • #2: Android/iOS 実機上での自動テストをより楽に有意義にする為に 端末管理・イメージ転送・動画記録等の周辺情報のノウハウ共有 を始めます
  • #5: 株式会社セガ 開発技術部の廣島です 主にツールやライブラリの開発をしてきました 最近はデザイナ向けのGitツールを開発したり、テストの自動化、マルチプラットフォーム対応と言った仕事が中心になっています 本日は宜しくお願いします
  • #6: 本講演に関する注意事項です こちらの講演では撮影、SNSへの投稿は可能となっています。資料も後日CEDILに公開されます 講演中の質問も可能となっていますので、コメント欄に書き込みをお願いします また講演後に Zoomによる質疑応答も行います
  • #7: 本日のアジェンダとなります まず自動テスト全体の流れについて、お話をします そしてテストとその周辺環境に関してとりあげます ここまでを私が担当します その後担当を交代して 具体的な環境構築の説明をしたあとに、運用時に発生した問題とその解決方法を共有します 最後に今後の展望について話します 前半部分では、Android/iOSの実機を用いて自動テストを実行する際の 全体の流れやテスト以外の周辺の環境に関して、私たちが構築した環境を例に挙げてお話していきます
  • #8: まずは私達が構築した自動テスト環境に関して説明します
  • #9: こちらが私達が作った自動テスト環境の構成図になります Macと端末だけです、非常にシンプルです 作成した環境はオンプレミス環境でMacと端末をUSBで接続しています テストフレームワークに関しては、このセッション中で補足の説明を行います
  • #10: 本講演ではこの部分、マシンと端末とのやりとりを中心にお話をしていきます
  • #11: 続いて環境構築の際に使用したソフトウェアに関して紹介しておきます RPAツールや録画ソフトなどをインストールしています、個々の詳しい内容に関してはセッションの後半でお話します
  • #12: 続いて登場人物を紹介します ビルド、端末制御、録画担当のMacです iOSアプリケーションののビルドを行う必要がある為、Androidと両立する為にMacを採用しました 主な役割はアプリケーションのビルド、端末情報の収集、アプリケーションのインストール、起動、ミラーリングした画面の録画を行います
  • #13: 続いてモバイル端末です テスト対象なので役割としてはアプリケーションの実行を行います ビルドを行うマシンとはUSBによる有線接続 テストフレームワークとはWi-Fiで通信します
  • #14: こちらが大まかな全体の流れになります 準備フェーズ、テスト実行フェーズ、終了フェーズに分けて説明していきます こちらはAndroid版となります、iOS版とは微妙に差があります
  • #15: こちらがiOS版の流れになります Androidに比べ少し工程が増えています それぞれのフェーズについて少し掘り下げて説明します
  • #16: 各フェーズについて触れる前に、この講演で扱わない事象に関して列挙しておきます Android/iOSのアプリケーションのビルド テストの実行そのものに関して テスト結果の解析や通知、分析など 既に多くの方が実践されていますし、多くの講演も行われている事から、この講演では共有しません
  • #17: それでは各フェーズに関して少し掘り下げて説明をしていきます まずは準備フェーズです 準備フェーズでは 端末情報の取得を行い 続いてミラーリングの準備を行います、私達が構築した環境ではミラーリングした画像を録画します 続いてAndroidの場合はここでビルドを行い出来上がったアプリケーションを転送します そして録画用のソフトを起動します ここまでが準備フェーズです 補足ですが色が薄くなっている箇所が先ほど説明した本講演では積極的に取り上げない部分です
  • #18: 続いてテスト実行フェーズです、テスト実行フェーズはAndroidとiOSで少し工程が違います まずはAndroidから説明します アプリケーションの起動を行います 続いてミラーリングした映像の録画を開始し、テストを実行します テストが終了したら、録画を停止し、アプリケーションを終了します 録画したファイルを所定の位置に移動します 私達が構築した自動テスト環境では、この工程をテスト毎に繰り返します
  • #19: こちらはiOS版のテスト実行フェーズになります Android版との違いは、テスト毎にXcodeビルドを行う点です
  • #20: 最後に終了フェーズになります 録画用ソフトの終了 ミラーリングの停止 そしてテスト結果の解析と通知処理を行って終了となります これで私たちが構築した自動テスト環境の流れに関しての説明は終わりです
  • #21: 具体的な環境構築の話の前に、 なぜ実機によるテストが必要なのか テストフレームワークに関して オンプレ自前環境 vs クラウドサービス 自動テストと録画について それぞれの項目についてどういった点を考えたのかをお話していきます
  • #22: なぜ実機でテストを行うのでしょうか 答えは明確で、エミュレーターによるテストだけでは不十分だからです 端末固有の問題であったり、端末とバージョンで発生する問題であったり 実機でなければ発生しない問題が存在する為です
  • #23: 私達も今までの開発で 呼び出した関数がそもそも存在していなかったり、ネイティブで実装されている関数の挙動が変わっていたりしました どちらも実際にその端末で問題が発覚するまで、正しく動くと思われていました こういった点からも実機でのテストは重要で出来る限り行った方が良いでしょう
  • #24: 続いて、テストフレームワークに関して説明をします ちょっと環境構築の話題とは外れるのですが、馴染みの無い方がいるかもしれませんので補足します
  • #25: テストフレームワークの主な役割としては以下のものがあります プロジェクトの作成 スクリプトの作成 スクリプトの実行 レポートの出力 こういった機能があるものが主流です
  • #26: 代表的なテストフレームワークとしては .NET向けにNUnit,xunit,MSTest.TestFrameworkなどがあります NUnitやxunitはシェアも大きく、情報も多く得られます MSTestはMicrosoftがリリースしているFrameworkです そして、ブラウザ用のSelemiumであったりモバイル用のAppiumが有名です
  • #27: テストフレームワークを選定する際は、自動化を視野に入れた選定を行う事がポイントです 例えばAppiumのようにネットワーク経由でテスト操作可能なフレームワークを採用すると環境構築がしやすくなります
  • #28: またゲームの場合は独自のフレームワークを作成している事も多く、ゲームの中に実装されている事もあります テストフレームワークの選定や実装を行う際は自動テスト環境の構築までを視野にいれて行う事をお勧めします
  • #29: ここからは自動テスト環境をどこに用意するのかについてお話していきます
  • #30: 最近ではクラウドのテストサービスが多く登場しています 以前はあまり一般的ではなく、かつ高価だったこともあり 端末やマシンを自前で用意する必要がありましたが、昨今さまざまなサービスが存在し選択肢は広がっています AWS Device Farmなどが有名です
  • #31: 実際に自動テストを走らせる環境として オンプレミス上に自前で環境を用意するのが良いのか クラウドサービスを利用するのが良いのか どういった点で選ぶのが良いかまとめました
  • #32: まずはクラウドサービスの特徴です 並列実行に強いです 端末を用意する必要がありません さらに最近のサービスですと端末の種類も豊富に用意されています
  • #33: 続いてクラウドサービスのデメリットです 価格はオンプレに比べ高価です また使用可能なテストフレームワークに制限がある事が多いです Appiumに対応しているサービスは比較的多くあります サービスによっては端末を誰かが使用していると使用できないと言う事もあるようです
  • #34: 続いてオンプレミスの環境の特徴です まずは予算的に優位な点 そして自前のテストフレームワークの採用が可能である点、特にゲームの場合は独自のゲーム内フレームワークを組んでいる場合も多いのではないでしょうか 続いてテストを実行していない時は別の用途に転用が可能な点もメリットです。 既にデイリーでビルドを行う環境がある場合などは、新たなマシンを用意する必要はありません
  • #35: 続いてデメリットです 実機テストと言う点で端末は用意する必要があります 構築・運用については全て自前です さらに構築に関する知識が必要となります ただこの知識に関しては 当講演で解消可能となっています
  • #36: その他の選択肢としてクラウドとオンプレのハイブリッドとして ビルドからデプロイまでをクラウドで行いテストのみをオンプレミスで行うと言う方法を考えてみました Azure pipelines self –hosted agentを用いて チェックアウト、ビルド、XcodeビルドまでをAzurePipieline上で行い、テストは実機を用いたオンプレミス環境で行う形です すでにAzure上にビルドなどの環境を用意されていた場合でも、オンプレミスのMacを用意すれば本講演の内容を活用できます
  • #37: 私達はオンプレミスを採用しました どういった理由でオンプレミスを採用したかですが 一つは予算面です。私達が間接部門と言う事も影響が大きかったと感じています もう一つはテストフレームワークの問題です 私達は独自のテストフレームワークを採用していた為に適合しませんでした さらに、導入するプロジェクトの秘匿性が高くテスト環境を外に出すリスクが取れなかった事が挙げられます 以上の3点から私達はオンプレミス環境を採用しました ただどちらを選択するかは、プロジェクト毎に判断が必要です
  • #38: ここから、話題が変わってテスト実行中の録画に関してお話します
  • #39: 自動テストを行う際には録画を行う事を強くお勧めします 録画が無い自動テストを想像してみてください ある日通知が飛んできます テストAが失敗しました 通知には呼び出し履歴が添付されています なるほど、あそこで落ちたのかよし直そう、とはならないですよね まずは不具合を再現しようとしますよね しかしエラーを再現するのも一苦労です テストを録画する事には再現性の低い不具合の発生手順の確立であったり 不具合の内容確認の容易性を高めると言った効果があります 録画とテストは切り離せない関係にあると言っても過言ではないでしょう
  • #40: では実際に自動テストを行う際にどういった手段で録画を行うのか 以下の4つ手法に関して考えていきます ミラーリングした映像を録画する方法 端末で録画を行う方法 HDMI分配器を利用する方法 カメラを用いて直接撮影する方法 それぞれの方法に関して特徴を上げて考えていきます
  • #41: まずミラーリングです メリットとして タイトル毎に録画機能を実装しなくても良い点 録画ファイルの取り回しが簡単 などが上げられます 特に録画機能を実装しなくても良い点は、実機でテストを行う事の趣旨からとても重要です 録画機能のデバッグやテストはどうするのかといった問題が出てきてしまうからです デメリットとしては複数端末の同時録画が難しいと言う点を挙げました
  • #42: 続いて端末内で録画を実行する方法です メリットとしては複数同時端末の録画が可能です デメリットとしては、 録画機能の実装が必要 端末ごとにデバッグが必要になるかもしれない、バージョンによって動作が不安定になる事もあるでしょう 録画したファイルの取り扱いが複雑になるといった点もデメリットと言えるでしょう エンコーディングをPCで行う場合は、その部分の自動化も行う必要があります
  • #43: つぎはHDMI分配器を利用する場合です メリットは 環境構築が容易な点です タイトル毎に録画機能を実装しなくても良い点 デメリットとしては 端末との相性問題や 端末数分の機器を用意する必要がある点です
  • #44: 最後にカメラによる直接録画です メリットは 環境の構築が比較的容易な点 実装を行う必要が無い点が上げられます デメリットは テストと録画データの紐づけを行う必要がありデータの扱いが複雑になります また端末数に応じたカメラを用意する必要があります
  • #45: 私達はミラーリングを採用しました 採用の理由としては 最も大きな理由はタイトル毎端末ごとに録画機能を実装しなくて良いと言う点 その他には、録画したデータの取り扱いが一番容易であった点 複数の端末で実行したいという点 以上が録画方法にミラーリングを採用した理由になります
  • #46: 端末での録画を行う場合についての補足です AndroidはMediaProjectionAPIを利用して実装を行います、iOSではReplayKitを用いて実装します どちらも、端末やOSのバージョンなどに気を使いつつ実装する必要があります
  • #47: ここで前半が終わりとなります ここまでの内容に関して振り返ります テストフレームワークこちらは自動化を視野に選定・実装を行いましょう、ネットワークで駆動する形にすると自動化はしやすいです そして自動化環境ですが現在は実機テストを行う為のクラウドサービスなども多く存在しています。 予算やプロジェクトの状況によって最適な答えは変わります そして自動テストと録画の関係ですが、非常に相性が良いです。何らかの形で録画を行う事をお勧めします
  • #48: それでは後半は私、竹原が担当させて頂きます 軽く自己紹介させて頂くと、自動化やツール、ネットワークまわりが主戦場で、最近ではサウンドにも手を出し始めました、よろしくお願いします それではさっそく講演に戻りたいと思います
  • #49: 廣島さんからはテストの全体像や環境構築の前段の話をして頂きました ここからは、私、竹原から具体的な環境構築の説明と、運用トラブル事例を紹介させて頂きます かなり分量があるので少し駆け足になってしまうと思いますが、よろしくお願いします
  • #50: 具体的な環境構築方法の紹介に入る前に、一点資料の見方について共有です 私のパートでは Android と iOS の説明が交互に入り乱れています 資料の右上にどちらのプラットフォームの説明かを表すアイコンを入れておりますのでこれを目印代わりにしてください
  • #51: それでは紹介を始めます まずは準備フェーズの各種処理について説明します
  • #52: 最初は端末情報の取得についてです
  • #53: テストを行う前に、ビルドしたアプリケーションイメージを実機に転送し、起動しなければいけません この転送・起動には、Android ではデバイス名と端末固有のデバイス ID が、 iOS ではデバイス名とこちらも端末固有の UUID が必要となります テストフレームワークによっては端末と通信を行う IP アドレスも必要になると思いますので、そういった場合はこのタイミングで取得しておくと楽です
  • #54: それでは、 Android の端末情報の取得についてから説明していきます Android は開発用ツールである adb のコマンド結果をパースすれば OK です デバイス名、 ID は adb devices を l オプションつきで実行すると一覧が列挙されるので、ここからテストしたい端末をパースします IP アドレスは取得したデバイス ID を用いて shell ip addr show オプション付きで呼び出した結果をパースします
  • #55: 私たちは MacOS 上に Jenkins で環境を構築しましたので、当講演では具体例として Jenkins 上で実行する groovy スクリプトや shell を紹介します こちらのページは Jenkins の Extended Choice Parameter Plugin を利用してビルドパラメータで端末IDを選択可能にした groovy 例です 右上にあるような形で端末名を選択してテストを実行可能になります スクリプトの詳細は残念ながら説明する時間がありませんので、スキップさせて頂きます これから紹介するスクリプトも詳細は追わずに同様にスキップしていきますので、興味のある人は資料公開後確認してみてください
  • #56: こちらは IP アドレスの取得例ですが、一点注意事項があります VPN 等仮想インターフェースに IP アドレスが割り振られている場合、 Ip addr show の表示結果が変わります 構築する環境に合わせてこの辺の実装は修正してください
  • #57: 次に iOS の端末情報取得方法です デバイス名、 UUID は xcrun コマンドをパースすることで取得できます しかし、 iOS では MacOS から shell を使って直接 IP アドレスを取得する方法がありません いくつか解決手段はありますが、 Bonjour の利用をお勧めします
  • #58: Bonjour は MacOS や iOS に標準で搭載されている、Multicast DNS を利用した、デバイス名をホスト名のように扱ってアクセス可能にする仕組みです Bonjour を使うと、デバイス名.local で名前解決を行い、アクセスすることが可能になります デバイス名は先ほど xcrun をパースして取得しているので、自動化環境への組み込みも簡単です
  • #59: Bonjour を環境に組み込むには 自前で Bonjour を実装し IP アドレス取得しておくか Bonjour 対応アプリを MacOS 側で起動しておくかのいずれかの対応を行う必要があります 自前実装はしんどいですし、対応アプリは起動しておくだけで OS 側が デバイス名.local を自動的に名前解決してくれるようになり非常に楽なので、対応アプリを起動しておく方をお勧めします 対応アプリには、このスクリーンショットのような「ミュージック」が該当します
  • #60: とても便利な Bonjour ですが、注意事項も存在します まず、iOS に デバイス名.local でアクセスする場合は同一 LAN 上に端末と Mac が存在している必要があります また、ActiveDirectory と併用する場合は、ActiveDirectory 側のローカルドメイン名に .local を使わないよう注意する必要があります
  • #61: 非同一 LAN 環境、例えば端末が接続されている Wi-Fi と Mac が接続されているネットワークのセグメントが異なるような社内ネットワークで環境構築をする場合は Bonjour は利用できません この場合代替手段として、 MacOS 上で USB 接続されている iOS 端末のパケットをキャプチャし、その結果をパースすることで IP アドレスの取得を実現できます 特殊な環境、且つ長くなる為にここでは説明を省きますが、詳細を Appendix として資料末尾に記載していますので気になる人は後程ご確認ください 具体例として Unity アプリケーションでの IP アドレスの取得について掲載してあります
  • #62: こちらは iOS の端末情報取得の Jenkins 例です この実装で Android 同様に Extended Choice Parameter でビルドパラメータ化することができます そして、ここで取得したデバイス名をもとに、ネットワーク接続が必要になった場合は .local を付けてテストを行います
  • #63: 次は端末上の映像のミラーリング方法を紹介します
  • #64: Android のミラーリングですが、公式にミラーリングソフトがない為に OSS やフリーのツールを活用します 私たちはこれらの OSS やツールを検証しましたが、最終的には scrcpy を採用しました ApowerMirror は録画機能があったりと魅力的だったのですが、GUI 操作が必要な箇所が多く、自動化と相性が悪かったので諦めました その他のものは、更新が停止していたり、Mac 版のクライアントソフトが存在しなかったりした為に選択から外れました
  • #65: scrcpy は Apache License 2.0 で公開されている OSS です Shell から操作可能で、オプションでビットレートやフレームレート等様々な設定が可能です また、端末側に scrcpy のインストールが不要なので自動化とも相性が良く、USB からミラーリングを行えるので挙動も安定しています ミラーリング映像のタッチ操作機能もあり、これによりリモート環境越しに端末の操作を行うことが可能で、自動環境構築時のデバッグが捗ります
  • #66: そんな便利な scrcpy ですが、弱点もあります 音声ミラーリングの機能はありません、後述する別の OSS を利用する必要があります 録画機能はあるものの、無圧縮で録画する為に自動化環境で用いるには後段でエンコーディングを行う等しないと、ディスク容量が厳しくなる可能性があります 最後に、コマンドで起動後、この動画のように処理が返ってこないので MacOS 上の Jenkins で使うには少し工夫が必要です
  • #67: こちらが scrcpy を Jenkins で使う為の工夫です 3 通りあります ProcessTreeKiller から逃れる Pipeline で並列化して scrcpy のジョブが処理終了まで終わらないようにする AppleScript を使って Jenkins から切り離す これらの中で ProcessTreeKiller から逃れる方法が一番簡単なので、今回はその設定方法を紹介します
  • #68: Jenkins は、ビルド中にジョブによって生成されたプロセスを確実に強制終了するためにプロセスを記憶してジョブ完了時に kill する ProcessTreeKiller という機能を持っています この ProcessTreeKiller のせいで、 nohup を指定してプロセスをバックグラウンド実行したとしても、ジョブ完了時にそのプロセスは終了してしまいます では、どうすれば ProcessTreeKiller を抑制できるのでしょうか?
  • #69: shell でジョブを実行している場合、環境変数の BUILD_ID に dontKillMe プロセスパス を入れることで回避可能です その後 nohup を付けてバックグラウンド実行することで scrcpy のような終了を待つプロセスを Jenkins から切り離す形で起動することができます
  • #70: Pipeline の場合は BUILD_ID の代わりに JENKINS_NODE_COOKIE に dontkillMe を設定することで回避可能です この場合プロセスパスの指定は不要です
  • #71: ProcessTreeKiller の問題が片付いたので、次は Android で音声もミラーリングする話です 音声ミラーリングには、 sndcpy という scrcpy とセットで使う為に作成されている OSS を使います
  • #72: sndcpy は内部的に Android 10 から実装された AudioPlaybackCapture API を使用しています この為、 Android 9 以前の OS の端末では音声ミラーリングはできません また、scrcpy と違って端末にアプリケーションのインストールが必要です
  • #73: sndcpy は同リポジトリ上に同梱されている sndcpy という同名の shell を叩くことで端末へのインストールをはじめとする一連の流れを全て実施してくれます 流れをざっと説明すると、 1. sndcpyを端末へインストール 2. 端末上で sndcpy 起動 3. 端末側で音声ミラーリングの警告ポップアップが出る、これは AudioPlaybackCapture API を使った際に Android OS 側が出すものです 4. ポップアップを閉じる 5. PC 側で VLC というフリーのソフトを起動する という感じです 5 の VLC は、 音声ミラーリングをしたストリームデータを MacOS 側に繋げる役目を担っています。この VLC も別途インストールする必要があります そして、この中の 4 が曲者で、表示されるポップアップの「今すぐ開始」を手動で選択をしてあげる必要があります これは Android 側の GUI の操作なので自動化と非常に相性が良くない挙動です
  • #74: どうにかこのポップアップを表示しないようにしたいのですが、前述した通りポップアップは Android OS 側が握っているものなので、抑制する方法が見つかりませんでした そこで、最終手段である RPA ツールの Automator を用いて自動で GUI 操作を行うことにしました
  • #75: Automator はユーザのデスクトップ操作を記録して再現可能な所謂 RPA ツールで、MacOS に標準搭載されています 記録後はアプリケーションとして保存することが可能で、とても取り回しが良いです 内部的には AppleScript というスクリプトで構成されています。AppleScript については次のページで解説します これだけ聞くととても便利そうなツールに見えますが、RPA ツールの宿命であるレイアウト変更、例えばボタンの位置が変わったり、ウィンドウのサイズが変わったり、というようなものには弱いです ボタンについては座標で記憶せず内部的な名前で処理する等かなり頑張っている感はありますが、それでも先ほど挙げた Android の画面内の GUI を操作する、というような座標で記憶するしかないような操作に関してはどうしても限界があります この弱点が最終手段と称したゆえんです
  • #76: Automator の実例に入る前に、実装スクリプトである AppleScript について理解しておくと、作成した Automator アプリケーションの挙動を修正したい場合に役に立ちます AppleScript は Apple 製のスクリプト言語で、Automator 経由でアプリケーション化したり、shell から呼び出すことが可能です できることは Automator と同等で、キーボードやマウス操作等をスクリプトから実現可能です 具体的なコードは後程登場しますのでそちらを参考にしてみてください
  • #77: とても便利な AppleScript ですが、世の中に使い方の資料があまり多く出回っていないのが弱点です オンライン上にある公式ドキュメントは情報が古い部分があるので、困ったら MacOS 上で AppleScript を開いた際のメニュー「用語説明」の解説も参考にしてみてください Quick Time PlayerのAPI等様々なヘルプも記載されています
  • #78: また、画面ロック中は当然キーボードやマウスの操作は意図した通りに動きません セキュリティ的に画面ロックを行いたい場合は、該当処理の前後で画面ロックを解除、再ロックの処理を挟む必要があります このあたりの問題も、先ほどのレイアウト変更に弱いのとあわせて、RPA ツールが自動テストに向いていない点となります ちなみに、画面ロックの自動化は MacOS の Remote Desktop 機能に対応した AppleScript を用いると実現可能です
  • #79: それでは Automator と AppleScript、どう使い分けるのが良いのでしょうか? まず、特定のキーをストロークするような簡単な処理であれば AppleScript で実装してしまうのが手っ取り早いです アプリケーションを立ち上げて、マウスで特定のボタンを押して画面操作を進めるような複雑な処理の場合は AppleScript での実装はしんどいので Automator を活用しましょう また、Automator では記憶した操作をあとで AppleScript として修正することが可能です 記憶時に失敗して複雑な操作を何度もやり直すような面倒な手間が避けられるのでとても便利です
  • #80: それでは、本題に戻って Android のポップアップのボタンを Automator で押しているところをお見せします scrcpy をアクティブにして「今すぐ開始」にカーソルを合わせクリック、という操作が行われています
  • #81: こちらがこの自動操作を Automator で開いた際の画面です Automator 上では先ほど記憶した操作がこのように分解されています このうち、「ATCウィンドウを手前に表示します」という項目は、ポップアップの「今すぐ開始」を押した操作になります Android 内の GUI 操作なので Automator 的にはボタンも何もないウィンドウをクリックしたとみなし、このような説明文になっています
  • #82: この Automator の画面から、先ほど触れた AppleScript 化しての修正を行うことが可能です まず対象項目を画面下にドラッグ&ドロップすることで、イベントウィンドウに記憶された各種操作をコピーして編集可能にできます
  • #83: コピー先の修正は、各種操作の項目が元々あったイベント欄のものには反映されないので注意してください 更に各種操作の内容はこのコピー操作を通じてしか変更できません つまり、元々のイベント内の各種操作の項目の内容は直接変更できません
  • #84: ですので、記憶した操作を編集したい場合は、イベントウィンドウにあるすべての操作項目をまずはコピーし、 イベントウィンドウ内の各項目はイベントウィンドウごと削除しておきましょう
  • #85: 説明の為に既に前のページでは編集を行ってしまっていますが、こうした形で各項目のコピーを作成してから AppleScript 化されたものを編集していくのがお勧めです 修正後は、金づちアイコンをクリックすると構文の強調表示を行ってくれますので、そこからスクリプトが間違っていないかチェックしましょう 画面は Automator を立ち上げてから、操作開始するまでの待ち時間を 2.2 秒から 1 秒に修正した例です
  • #86: 無事 Automator アプリケーションの作成と修正ができました 自動処理では、このアプリケーションのポップアップ操作が完了してから次の自動処理に進む必要があります しかし、shell からこのアプリケーションを呼び出す場合、open コマンドでは終了を待つことはできません この問題を回避する為に、Automator アプリケーションの終了を待つ AppleScript を作成しました
  • #87: こちらがその AppleScript です 引数で受け取ったコマンドを実行し、そこで立ち上がったプロセスが終了するまで repeat ループで待機します AppleScript はこうした処理を手軽に書けるので、使いこなせるようになると自動化が非常にはかどります。お勧めです
  • #88: それでは作成した Automator アプリケーションの処理を先ほどの sndcpy shell の間に差し込みましょう Automator での操作はポップアップを閉じるだけに留めたいので、その他の処理はもとの sndcpy スクリプトを分割して対応しました 後半の VLC に関する処理を独立させ、前半はそのままという形で分けています
  • #89: こちらは分割した sndcpy スクリプトの 1~3 の部分となります 気になる方は後でご確認ください
  • #90: こちら後半部です こちらも気になる方は後でご確認ください
  • #91: 準備が整ったのでいよいよ Jenkins でミラーリング処理の自動化を行います まず scrcpy をバックグラウンド実行で呼び出します
  • #92: sndcpy は前述した通り三段階に処理を分けて呼び出します
  • #93: 最後に MacOS 上ではなく Windows 上でミラーリングを実現したい場合の補足です scrcpy/sndcpy は Windows にも対応しているので基本的には今まで紹介した処理を bat 化するだけで実現可能です Windows には Automator はないので、ポップアップの抑制は別の Windows 対応の RPA ツールを使いましょう
  • #94: ようやく Android のミラーリングの説明が終わりました…… この調子でどんどん進めていきますので、気になるところがあった方は後日資料を見返して頂ければと思います さて、iOS は MacOS に標準にインストールされている QuickTimePlayer でミラーリングが可能です QuickTimePlayer を使った自動化については何点かはまり処があるので紹介します
  • #95: まず、Quick Time Player はミラーリングに加え、ミラーリングした映像を録画することが可能です しかし、scrcpy 同様に録画ファイルが無圧縮なので自動化 PC のディスク容量を気にする場合はエンコーディングが必要となります 詳しくは後述する録画の項目で解説します
  • #96: また、これまた scrcpy 同様に、ミラーリングした映像からマウスで操作が可能です ただ、 shell からの起動オプションが用意されておらず、キーボードショートカット操作もあるものの肝心のミラーリング操作において対応していないものがあったので、今回の自動化との相性はあまりよくありません しかし、他に自動化に使えるミラーリングツールが見つからなかった為、最終的に Automator を使って QuickTimePlayer を操作することにしました
  • #97: こちらが作成した Automator アプリケーションの様子です sndcpy のポップアップクローズより若干処理が多いですが、内容的にはシンプルで、 QuickTimePlayer を起動、アクティブにし その後キーボードショートカットにより新規ムービーの作成を起動します 録画ウィンドウが開いたらミラーリング対象のデバイスを選択します これにてミラーリングが開始されます
  • #98: Automator でアプリケーション化できてしまえば jenkins での処理実行は簡単です いつもの通り dontkillme 設定をして作成したアプリケーションを呼び出しましょう sndcpy の際は処理が完了するのを待ちましたが、ミラーリングの開始は後段にいろいろな処理を挟むので、待たずに投げっぱなしにしています 気になる人はポップアップクローズ待ちと同様にスクリプト経由で呼び出してください
  • #99: 実は、先ほど紹介したスクリプトでは Automator で操作記録時にミラーリングする端末を決め打ちで指定しているので、一つの Mac に複数のデバイスを接続しているような環境に対応できません 端末毎に Automator で操作記録するのは現実的ではありませんから、 Android のようにミラーリングするデバイスを選択できる必要があります
  • #100: 順当に考えると、 Automator アプリケーションにミラーリングする端末名を渡して、それを選択するようなスクリプトを作成すれば問題は解決できそうです しかし Automator アプリケーションは自分達が調べた限りは引数としてファイルパスしか渡せないようでした そこで、 引数で端末名を渡す方式は諦めて、呼び出し元で環境変数に設定したデバイス名を AppleScript 内で読み込むことにより対応しました
  • #101: こちらが修正した AppleScript です 元の実装では Automator で記憶した際に使っていたデバイス名が埋まっているので、これを動的に呼び出し元から差し替えられるようにします 修正後の実装では、環境変数 DeviceName にデバイス名が export されているものとして読み込み処理を行い、元の実装のデバイス名の部分に差し込みます
  • #102: 複数デバイス版の Automator アプリケーションに対応した Jenkins ジョブはこちらです ノーマル版に、デバイス名を環境変数として指定する処理を挟むだけの非常に簡単な修正で済みました ただし、先ほどのスクリーンショットに写っていたデバイス名ひらがなの あいふぉん は文字コードの関係で、そのままでは正常に動作しません なるべくアルファベットのデバイス名で環境を構築するのをお勧めします
  • #103: 次はアプリケーションイメージを端末へ転送する処理です
  • #104: Android ではアプリケーションを端末に転送する処理、端末上で起動する処理をそれぞれ adb によって別々に実行できます そこで、ビルド・転送は準備フェーズに実行しておき、起動のみテスト毎に実行することでテスト実行の効率を上げることができます テストが増えてくるとこうした細かい処理に掛かる時間が馬鹿にできなくなってきますので、なるべく準備フェーズに処理は逃がしましょう 逆に iOS ではこのタイミングでアプリのビルドや転送ができないので Android に比べて若干効率が悪くなっていますが、それでも工夫次第では改善することができます 詳細はテスト実行フェーズにて紹介します
  • #105: android でのアプリケーションイメージの端末への転送はとても簡単で、 adb のコマンドを叩くだけで OK です
  • #106: こちらが Jenkins の実行例です 先ほどのコマンドのパラメータをビルドパラメータに置き換えただけですね
  • #107: いよいよ準備フェーズ最後の手順である録画にやってきました
  • #108: scrcpy/Quick Time Player の録画機能は前述した通り無圧縮ですので、テストが増えてくるとすぐに録画マシンのディスク容量を食いつぶしてしまいます そこで、実運用的にはエンコーディング処理を挟む必要があります また、 scrcpy の録画機能は sndcpy と連動しておらず、音を拾うことができないので、録画に音声も含めたい場合には機能不足です そこで、別のソフトの検証を行った結果、私たちは OBS Studio を採用しました
  • #109: OBS Studio は録画・配信用の OSS です シェルの起動オプションとして、ウィンドウサイズや録画範囲などの細かい指定が可能です GUI ツールですが、様々な操作のキーボードショートカットが有り、更にwebsocket経由で操作も可能なので、 自動化との相性も悪くはありません scrcpy や QuickTimePlayer と違い、録画と同時にエンコーディング可能なのもありがたいポイントです youtube や twitch 等の配信でよく利用されており、更新が非常に活発なのも採用の決め手となりました
  • #110: OBS Studio の基本的な使い方は web 上に公開してくださっている方が多数居るので全体説明は割愛して、自動化に関連する項目だけ紹介します まず、OBS はプロファイル単位で種々の設定が可能で、起動時の引数でこのプロファイルの指定もできます これにより、自動化用にプロファイルを何種類か作っておき、端末単位で使い分けるということができます この際、プロファイルの名前にはデバイス名や ID を指定すると処理が楽になるのでお勧めです
  • #111: 録画を行う画面全体を OBS ではキャンバスと呼び、このキャンバスもプロファイル単位の設定となります テストする端末の数が膨大な場合、端末毎にプロファイルの作成するのは大変なので、複数の端末の解像度を包含する大きめのキャンバスを設定しておき、近い解像度やメーカー等で統一しておくのも良いでしょう 端末によっては録画画面に若干の余白ができてしまいますが、テスト用途なので私たちは気にしていません どうしても気になる場合は 出力サイズ変更(ソースサイズ) というウィンドウにキャンバスを合わせる機能があるので、その処理の自動化も行うと良いでしょう
  • #112: OBS では画面全体やウィンドウ単位等様々な録画対象を指定できます これはシーンという項目のソースで指定可能ですのでキャンバスと共に忘れずに設定を行いましょう 画面全体を録画するのは無駄なので、ミラーリングを行っているアプリのウィンドウをソース設定するのをお勧めします iOS では QuickTimePlayer のウィンドウ名が固定なのでこれを決め打ちで Android では scrcpy の起動時オプションでウィンドウ名を指定可能なので、全ての端末で統一した名前を付けて設定の手間を省きましょう
  • #113: シーンの設定が終わったらキーボードのショートカットを設定しましょう websocketを使った操作が理想ではありますが、実装はプログラマでないと厳しいと思いますので、今回はショートカットによる自動化を紹介します 実際の操作は後程説明します また、このショートカットもプロファイル毎なので、プロファイルをあまり細かく分けると設定が煩雑になる点には注意してください
  • #114: 最後に録音関連の設定を行います sndcpy で取り込んだ音声を仮想デバイスから取り込むことで OBS 上で録音を実施することができます これは SoundFlower というツールを用いると実現が可能です SoundFlower のインストール後はシステムの設定及び OBS 上で SoundFlower を忘れずに指定するようにしてください ちなみに、 M1 チップを採用している Mac ではこの SoundFlower は動かないとのことなので BlackHole というツールを使うと良いらしいです
  • #115: さて、事前準備が終わったのでいよいよ起動設定を行いましょう OBS は起動時の引数に --startrecording を指定すると、起動後自動で録画開始することが可能です また、先ほどから出てきているプロファイルの指定は --profile “name” で指定できます 他にも色々指定可能なので、気になる方は公式のドキュメントを参照ください
  • #116: ここまでの内容を落とし込んだ Jenkins のジョブはこのような感じになります 私達が構築した環境では、先ほど触れたようにテスト毎に OBS を起動するコストを回避する為に起動と録画開始は切り離しており、このタイミングでの録画開始はしていません
  • #117: OBS は Windows にも対応している為、Mac ではなく Windows 上に環境が欲しい場合も同様の手順で構築可能です Windows ではキーボード操作の自動化が可能なフリーのソフトが数多くあるので、ショートカットキー操作の自動化も簡単です
  • #118: ただし、Windows で録画環境を作成する場合はロック中やRDPで運用しているPCの録画をどうするか、という問題があります この問題は本筋から外れるので Appendix として資料の一番後ろに解決方法を共有してあります Windows で環境構築する場合は参考にしてみてください
  • #119: 長かったですがようやく準備フェーズが完了しました あとはテストをまわすだけ、といいたいところですが、アプリケーションの終了を挟まずに起動を継続したままテストを実行すると「別のテストの後に実行すると前提条件がクリアされて成功してしまうバグ」のような問題を踏んでしまう恐れがあります よって、テスト間で依存関係がない限りはテスト実行毎にアプリの起動・終了を挟む方が安全です ここからはこのテスト毎の実行環境の構築方法について共有します
  • #120: まずはアプリケーションの起動からです アプリケーションの起動は Android と iOS で必要な処理が異なりますのでそれぞれ共有します
  • #121: Android では、アプリの起動は転送の時同様に adb を用います
  • #122: こちらが Jenkins の実行例です
  • #123: 次に iOS のアプリケーションの起動です
  • #124: iOS のアプリケーションを端末で起動するにはビルド、転送の処理も一緒に行う必要がある為、この項目でまとめて紹介します
  • #125: まず、iOS ではアプリケーションの転送、起動に xcodebuild という Xcode のコマンドラインツールを使用します xcodebuild には、Xcode 8 から導入された、ビルドのみを行うことが可能な build-for-testing と転送/起動のみを実行可能な test-without-building というオプションが存在します これによりアプリのビルドと起動/転送を分けることができます
  • #126: と言いたい所なのですが、test-without-building には連続実行した場合に二回目以降のアプリの起動が失敗する、という問題があります これは、xcodebuild が内部的に利用している appium の状態が二度目以降にリセットされていない為に起こる問題のようで、 面倒なことにソースに変更が無い状態で build-for-testing でビルドし直すだけではこの状態はリセットされず、フルビルドし直す必要があります
  • #127: フルビルドは時間も掛かりますし、テスト毎に実行していては全てのテストが完了するまでに何時間あっても足りません
  • #128: そこでなんとか回避方法が無いか調査したところ、Xcode のキャッシュ内に生成された .app を削除して build-for-testing した後に test-without-building でアプリ起動することでこの問題を回避できることが分かりました この手順を踏んだ場合、 build-for-testing 実行時には .app が再生成されるだけとなり、フルビルドに比べて掛かる時間も非常に短くて済みます
  • #129: Xcode にキャッシュされた .app のパスはこちらです パスに埋まっているハッシュ値については、動的に取得する方法が見つかりませんでしたので、この値については一度手動で Xcode でビルドしてあげて、確認する必要があります 一度ビルドを行ってしまえばこの値は変わることはないようなので、頻繁に値を更新するような手間は不要です
  • #130: ただし、 test-without-building を使う為には xcodeproj 内に Xcode のテストである xctest が存在している必要があります build-for-testing 付きで xcodebuild を実行すると、この xctest が端末上で実行されるので、 何もせずに永久に待機し続ける xctest を作成、実行することにより疑似的にアプリの起動を再現することが可能です 永久に待機するので、テスト終了時にはアプリを強制停止するしかなく、xctest のテスト結果は常に失敗することになりますが、アプリの起動に利用しているだけなのでこの結果は無視しましょう xctest についての詳細は世の中に数多く出回っておりますので、今回の講演では割愛させて頂きます
  • #131: こちらが今まで紹介した手順のビルドの個所を Jenkins上 で実行している例です
  • #132: こちらが転送・起動です どちらも気になる方は後でご確認ください
  • #133: 最後に補足です 未検証ではありますが、現在β版である Xcode13 には -test-itreations というテストの回数を指定可能になるオプション -retry-tests-on-failure という失敗したテストをリトライ可能になるオプション -run-tests-until-failure という成功するまでテストを繰り返すオプション が追加されるようです これらをうまく使えば .app を削除してビルドし直す、といった面倒な手間は不要になりそうなので期待しています
  • #134: もう一点補足です xcodebuild を使わずに GUI 版の Xcode からキーボードショートカット経由で転送/起動を実現することも可能です しかし、RPA ツールでの自動化はこれまでお話したように最終手段であり、他の解決方法がある場合はなるべくそちらを採用するのをお勧めします
  • #135: いよいよテスト実行に近づいてきました…… このままブレイク無しで突っ走りますので、あと少しお付き合い頂ければと思います というわけで録画開始処理に関する共有です Android ではこの位置ですね
  • #136: iOS はこの位置の処理です 録画開始は iOS と Android で共通の処理となります
  • #137: というわけで録画開始処理に関する共有です 準備フェーズで OBS に設定した録画開始のショートカットを押せば終わりなのでとても簡単です 単純なキーストロークのみでいいので、ここは Automator ではなく AppleScript を直接使います
  • #138: AppleScript でキーストロークするのはとても簡単です AppleScript の仕様を知らないでもこのスクリプトを見るとなんとなくやっていることはわかるのではないでしょうか Jenkins からもこの shell を実行すればそれだけで OK なので、実例は割愛させて頂きます
  • #139: いよいよテストの実行にやってきました 後の処理は Android/iOS 共通となりますので、iOS 側の図の紹介は割愛させて頂きます
  • #140: 最初にお伝えした通り、今回の講演ではテストの実行そのものは共有の対象外ですが、少しだけ補足させてください テストの実行開始は、どんなテストフレームワークを採用しているかでタイミングが異なります 起動したアプリケーションに対して、外部からテストの実行を行うものを採用している場合、端末側のアプリケーションと MacOS 側テスト関連の準備が整ったこのタイミングになってからテストの実行を開始する必要があります
  • #141: 私たちが採用しているテストフレームワークも通信を行うタイプだったので、このタイミングでテストを実行開始しています 具体的には、起動している端末側のアプリケーションに対してテストフレームワークを経由してテストしたい動作を Json で指定します アプリケーションには侵入型のテストサーバプログラムが仕込まれており、テストフレームワークから受け付けた動作を実行し、その結果を返します テストフレームワークは返ってきた結果からテストの成否を判定します
  • #142: それでは、非通信型のテストフレームワークの場合はどうでしょうか? アプリの起動時にオプションで指定するようなものの場合も Android/iOS 共に指定が可能です adb は引数オプションが有ります xcodebuild はプリプロセッサマクロを活用すれば実現可能です コンフィグファイル等、テスト用のファイルを読み込んで実行する場合は、テスト毎に端末側にファイルを転送したり、特定のフォルダ下のファイルに対してファイル毎にテストを実行するように環境構築すると良いでしょう
  • #143: テストが終了したらテスト毎の後始末を行いましょう まずは録画を停止させます
  • #144: 録画終了は起動同様に AppleScript でキーストロークを行います こちらも同様にこの shell を Jenkins から呼び出せば OK ですが、 OBS は録画終了ボタンを押しても動画のエンコードの関係で即座に録画が終了しないこともあるので、自動化の際は次の処理に移行するまでに少しウェイトを入れてあげると良いです
  • #145: 次にアプリを終了してあげます
  • #146: Android は開始同様に adb で終了させます
  • #147: こちらが Jenkins の実行例です
  • #148: iOS アプリは起動を行った xcodebuild を pkill してあげましょう そのままなので Jenkins ジョブは割愛します
  • #149: 後片付けが終わったら録画ファイルのリネームを行います
  • #150: OBS はファイル名を柔軟に変更できますが、起動時引数のようなものでファイル名にテストの名前を埋め込むようなことはできません
  • #151: 動画ファイルにテスト名やその実行日時が埋め込まれていると、結果を確認している際に非常に分かり易くなります そこで、テスト終了毎に録画したファイル名にテストの名前を付ける形でリネームしています こちらの mv を使った例は動画ファイルを Jenkins の成果物として保存したいのでついでにフォルダの移動もしてしまっています
  • #152: これにてテスト実行フェーズは完了です あとは全体の後始末を行いましょう
  • #153: まずは OBS の後始末を行います
  • #154: OBS は pkill で終了すれば OK です
  • #155: ミラーリングの終了も
  • #156: scrpcy は pkill を sndcpy はアンインストールをしてあげます
  • #157: QuickTimePlayer も pkill で OK です これで後始末も完了です お疲れ様でした
  • #158: と言いたいところですが、もう少しだけ続きますのでお付き合いください 当項目では、これまであげた環境を実際に運用してみて発生した問題とその解決方法を共有します
  • #159: まず OS アップデートのポップアップ通知がテスト実行フェーズのループ中に入り込んで操作不能になる問題です Android/iOS 共にアップデートの抑制は可能ですので、面倒ですが端末毎に設定を忘れずに行っておきましょう
  • #160: 次は Automator の操作が時々失敗する問題です こちらは Automator で記録した際の設定、例えばウェイト値が状況によっては不十分だった為に発生する、RPA ツールではよくある問題でした 前述した通り、 Automator は AppleScript として修正可能ですので、テスト結果が安定しない場合はパラメータを変更する等細かい調整を行いましょう
  • #161: 次は、ノッチ対応のアプリを録画したら録画映像に妙な余白が発生した問題です
  • #162: こちらは余白は問題ではなく、単純にノッチ対応でアプリケーションの描画対象外になっている部分も込みでミラーリングされていただけ、という落ちでした この余白があるイコールノッチ対応の実装がうまくいっている、ということでもあるので、期せずしてミラーリングを用いた自動化環境では、録画データからノッチ対応の確認も行うことができることが分かりました
  • #163: 最後に、解像度の異なる端末でテストをした際に sndcpy のポップアップクローズが失敗する問題です この動画は分かり易さの為に少し極端に解像度を変えていますが、解像度の異なる端末で共通の Automator アプリケーションを用いるとこの問題が発生すると考えてください ミラーリングする解像度を合わせるような対策を行えば端末共通で Automator アプリケーションを使えますが、当然元の解像度が異なる場合はアスペクト比が崩れてしまいます とは言え、端末毎に Automator で操作を記憶するのは手間が現実的ではないのでどうするか悩ましい所です これは現状も解決できていない課題で、「今すぐ開始」を画像認識して押すようなアプローチが必要なのではないか、と考えています
  • #164: それでは、当環境の展望です
  • #165: まず、一端末ずつテストを実行すると時間が掛かってしまうので、複数端末を並列でテストしたいという要望があります 録画をどうするかが課題ですが、OBSのキャンバスをうまく活用すればいけるかも?と検討中です また、テスト中のパフォーマンスを取得したい、という話もあがっております こちらは端末ミラーリングの負荷の影響がどうしても出るので純粋な負荷をどう取得するのか、録画を切ればいけそうですがそれでいいのか等の検討を行っています
  • #166: 当講演の内容は以上となります 駆け足になりましたがご清聴ありがとうございました 当講演を聞いて、実機の自動化やってみようかなと思って頂けたり、困っていることのヒントが得られたようでしたら何よりです また、私たちの環境もまだまだ試行錯誤の途中ですので、他にもっと良いやり方があるようでしたら是非ご教授頂ければ嬉しく思います それでは皆様、良い実機テストライフをお送りください!