クラウドMac CIでiOS UIテストの失敗動画を記録する

CI/CD ·約 9 分

クラウドMac CIでiOS UIテストの失敗動画を記録する

クラウドMac上でUIテストが失敗したとき、アサーションとスクリーンショットだけでは原因を把握できないことが少なくありません。ポップアップが表示直後に消える、画面遷移が途中で止まる、キーボードがボタンを隠すといった問題は、連続した映像がなければ発生順序を確認できません。すべての録画を恒久的に保存するのではなく、テスト開始前に指定したシミュレータの画面収録を始め、成功時は削除し、失敗時のみ動画、ログ、結果バンドルをまとめて保存する方法が確実です。

テストデバイスと証跡の範囲を固定する

画面収録コマンドに booted をそのまま渡してはいけません。並列ジョブ、前回の異常終了で残ったデバイス、手動デバッグなどにより、複数のシミュレータが同時に起動している場合があり、別のデバイスが録画されるおそれがあります。まず対象ジョブ専用のデバイスを作成するか既存のものを検索してUDIDを取得し、そのUDIDを起動、テスト、録画、クリーンアップの各処理に渡します。

DEVICE_NAME="CI-iPhone"
RUNTIME="com.apple.CoreSimulator.SimRuntime.iOS-18-0"
DEVICE_TYPE="com.apple.CoreSimulator.SimDeviceType.iPhone-16"

UDID="$(xcrun simctl list devices available -j |
  plutil -extract devices json -o - - |
  jq -r --arg name "$DEVICE_NAME" '
    .. | objects | select(.name? == $name) | .udid
  ' | head -n 1)"

if [ -z "$UDID" ]; then
  UDID="$(xcrun simctl create "$DEVICE_NAME" "$DEVICE_TYPE" "$RUNTIME")"
fi

xcrun simctl boot "$UDID" 2>/dev/null || true
xcrun simctl bootstatus "$UDID" -b

ランタイム識別子はインストールされているXcodeによって異なります。すべてのマシンに同じバージョンがあると仮定せず、パイプラインの実行前に xcrun simctl list runtimes で確認してください。複数のジョブを並列実行する場合は、状態の共有を避けるため、デバイス名にもジョブ番号を含めます。

録画の目的は失敗時のタイムラインを補うことであり、ログの代替ではありません。動画は「画面上で最初に何が起きたか」を示し、ログとxcresultは「テストフレームワークが何を記録したか」を示します。

録画プロセスを確実に終了する

simctl io recordVideo は継続的に動作するため、スクリプト側でPIDを保存する必要があります。テスト終了直後に強制終了シグナルを送ってはいけません。まず INT を送り、ツールが動画コンテナのインデックスを書き終えるのを待ってから、プロセスの終了を確認します。

ARTIFACTS="${PWD}/artifacts"
VIDEO="${ARTIFACTS}/ui-test.mp4"
RESULT="${ARTIFACTS}/UITests.xcresult"
LOG="${ARTIFACTS}/xcodebuild.log"

mkdir -p "$ARTIFACTS"
rm -rf "$RESULT"
rm -f "$VIDEO" "$LOG"

xcrun simctl io "$UDID" recordVideo \
  --codec=h264 \
  --force "$VIDEO" &
RECORDER_PID=$!

finish_recording() {
  if kill -0 "$RECORDER_PID" 2>/dev/null; then
    kill -INT "$RECORDER_PID"
    wait "$RECORDER_PID" || true
  fi
}

trap finish_recording EXIT INT TERM

H.264は通常、ブラウザやチケットの添付ファイルとしてプレビューしやすい形式です。後からフレーム単位の解析が必要な場合は、成果物を扱うシステムとの互換性を確認したうえで別のコーデックに変更できます。ただし、同じパイプラインで形式を混在させると、閲覧ツールや保存ポリシーの挙動が予測しにくくなるため避けてください。

テスト本来の終了コードを保持する

録画は補助プロセスであり、xcodebuild の結果を覆い隠してはいけません。最も確実なのは、エラー発生時の即時終了を一時的に無効化し、テストの終了コードを個別に保存してから録画を正常終了する方法です。tee でログを表示する場合は、パイプライン内にある xcodebuild の終了ステータスを取得する必要があり、tee の成功ステータスを誤って使ってはいけません。

set +e
xcodebuild test \
  -workspace App.xcworkspace \
  -scheme AppUITests \
  -destination "platform=iOS Simulator,id=${UDID}" \
  -resultBundlePath "$RESULT" \
  >"$LOG" 2>&1
TEST_STATUS=$?
set -e

finish_recording
trap - EXIT INT TERM

if [ "$TEST_STATUS" -eq 0 ]; then
  rm -f "$VIDEO"
  exit 0
fi

exit "$TEST_STATUS"

ここでは、テストが失敗してもすぐには終了しないよう意図的に構成しています。録画プロセスの終了処理を完了させる必要があるためです。resultBundlePath にはジョブごとに独立したパスを指定し、実行前に既存のディレクトリを削除してください。削除しないと、古い結果が今回の失敗結果に混在する可能性があります。

ファイルの存在だけでなく動画を検証する

0バイトのファイル、コンテナヘッダーしかない短いファイル、強制中断された録画は診断に役立ちません。保存前に少なくともファイルサイズを確認し、システムのメディアツールで再生時間を取得してください。テストが開始直後に失敗した場合、動画が非常に短くても不自然ではないため、再生時間のしきい値を高く設定しすぎないようにします。

確認項目 推奨アクション 失敗時の対応
ファイルの存在 test -f ログを保存し、録画欠落として記録
ファイルが空でない test -s 録画PIDとディスク空き容量を確認
再生時間を取得可能 メディアメタデータを照会 破損ファイルとして扱い、中身のないファイルはアップロードしない
デバイスの一致 記録したUDIDを照合 ジョブを中止し、誤ったデバイスをクリーンアップ
テスト結果バンドル xcresultディレクトリを確認 元のログを代替資料として保存

UDID、テスト開始時刻、録画パスをプレーンテキストの一覧に書き出し、動画と一緒に保存することもできます。アクセス資格情報、環境変数一式、機密情報をマスキングしていないコマンドラインは一覧に記録しないでください。動画そのものにも通知、テストアカウント名、業務データが映り込む可能性があるため、テストフィクスチャには専用の非機密サンプルを使用します。

並列実行、タイムアウト、残留プロセスに対処する

各ジョブには、専用のシミュレータ、結果ディレクトリ、録画ファイル名を割り当てる必要があります。booted、固定された artifacts/ui-test.mp4、共通のDerivedDataディレクトリを共有すると、並列ジョブが互いのファイルを上書きしてしまいます。ジョブ単位のディレクトリは、パイプラインが提供する一意の番号から生成し、終了時には成功したジョブの一時ファイルを削除できます。

外側のタイムアウト処理がテストを終了する場合でも、クリーンアップ関数が実行される時間を確保してください。まずテストプロセスに処理可能な終了シグナルを送り、trap が録画の終了処理を完了できるよう数秒待ってから、最後に強制クリーンアップを行います。次のジョブを開始する前に、親プロセスがすでに終了している simctl io の録画プロセスが残っていないか確認しても構いません。ただし、広範な killall は使用しないでください。同じマシン上で動作している別のジョブまで誤って終了するおそれがあります。

安定した保存対象は通常、失敗時の動画、xcresult 結果バンドル、元のビルドログの3点だけです。3点には同じジョブ番号を付け、保存期間も揃えます。これにより、失敗一覧から特定のジョブを開いた後、まず動画で画面の状態を確認し、次に結果バンドルからアサーションと添付ファイルを特定し、最後にログでコマンド、対象デバイス、終了コードを照合できます。過不足のない一連の証跡を構成できます。

よくある質問

bootedではなくUDIDを指定する理由は何ですか?

並列ジョブでは複数のSimulatorが起動する可能性があります。UDIDを明示すれば、起動、テスト、録画、後始末を同じ端末に限定できます。

録画した動画が再生できないのはなぜですか?

強制終了すると動画コンテナの索引を書き終えられない場合があります。録画プロセスへINTを送り、終了を待ってから検証します。

成功したテストの動画も保存すべきですか?

通常は不要です。成功時は削除し、失敗時だけ動画、ログ、xcresultをまとめて保存すると容量を抑えられます。

Debug M4

独占型Apple Silicon物理ノードで次のビルドを実行

契約期間とノードのリージョンを選択し、Mac Mini M4、16GB RAM、256GB SSD、支払額(USD)を確認して注文を送信します。

クラウドMacを今すぐレンタル