GitHub Actions Test Offloading - log5r/simple-media-player GitHub Wiki

GitHub Actions へのテスト集約

調査日: 2026年10月4日。対象コード: 3a8d74d7778fc2dd5440b095763a9f3313133b96。設定・コード・既存 CI ログと公式資料を調査した。新たなビルドやテスト実行、ワークフローの変更はしていない。

自動テストの実行を GitHub 提供のマシンへ移せば、開発用 Mac のテスト負荷を減らせる。ただし、全テストを一つの実行先へ追加するだけでは、端末別の検証漏れと CI 側の負荷集中が残る。macOS、iPhone Simulator、iPad Simulator の実行を分け、各マシン内の並列数を抑える構成を推奨する。

現在の CI と確認できた実績

対象コミットのワークフローは、main への push と main 向け PR を契機に、xcode-27 で macOS ビルド、iOS Simulator ビルド、macOS 単体テスト、lint を実行する。iOS の単体テストと全プラットフォームの UI テストは実行しない。

このコミットの成功した実行は次のとおりだった。時間は GitHub の各 step 開始・終了時刻から算出した。一回の実績であり、平均値ではない。

工程 所要時間
macOS ビルド 4分13秒
iOS Simulator ビルド 2分50秒
macOS 単体テスト工程(テスト用ビルドを含む) 1分51秒
job 全体 9分3秒

ログでは Swift Testing の448ケース・71スイートと、XCTest の1ケースが成功した。Swift Testing の実行本体は18.823秒だった。実音声再生を伴う cachedAudioLoadsAndPlaysDuringActualBulkImport と、実ウィンドウを使う MarqueeTextHitTestingTests も成功している。したがって、この2経路が hosted macOS で常に実行不能という根拠はない。一方、未実行の UI/iOS テスト全体の時間・メモリ使用量は、この実績から推定できない。

全単体テストのコマンドは -parallel-testing-enabled NO を指定している。成功ログの448件の test 開始を終了イベント(引数別ケースをまとめる with N test cases passed も含む)と対応付けると、開始済みで終了前の test は最大1件だった。現行 Xcode 27/Testing Library 2084/この実行では、Swift Testing も直列に実行されたと確認できる。別の版での動作や、一つのテスト内の独自 task の並列数までは、この観測から保証しない。

@Suite(.serialized) はその suite 配下を直列化するが、他 suite との並列実行を抑えない。worker process 数の上限と Swift Testing 内部の実行設定も区別する。失敗後の診断2 step は -parallel-testing-enabled NO を省略しており、全体実行と同じ並列条件ではない。Swift Testing の公式仕様、Apple の解説。

xcode-27 は公式の Public preview ラベルであり、self-hosted 専用のラベルではない。標準 runner の仕様は M1 の3 CPU、RAM 7 GB、SSD 14 GB。既存ログの image は xcode-27-arm64、20260928.0222.1、macOS 27.0だった。搭載ソフト一覧の既定 Xcode 27.0(27A266a)は手元と一致するが、手元の macOS は27.0.1である。SDK、Simulator runtime、実行 OS を個別に記録する必要がある。

このアプリで起きそうな問題

問題 根拠と影響 対策候補
CI 側でも負荷が集中する テストプランの両ターゲットは parallelizable: true。現行 CI は並列無効化で上書きしているが、全テスト追加時にこの指定を引き継がなければ負荷が増える。UI は3,000件の一覧操作、iOS fixture は起動時に60秒の WAV を3個生成する。RAM 7 GB のマシンで複数 Simulator/UI worker を動かすと、メモリ不足や表示待ち timeout が起こる可能性がある。これは未実測の予測。 一つの runner 内の UI worker/Simulator は最初は1にする。通常単体・UI・音声統合を分け、実行時間とピークメモリを測る。
一つの destination では全テストを網羅しない macOS 専用 UI は #if os(macOS)。iPhone と iPad の layout suites は異なる idiom を XCTSkipIf で除外する。 macOS、iPhone、iPad の3実行先を設け、実行件数と skip 件数を確認する。画面サイズと OS も明示する。
テストが成功表示のまま抜ける MusicAnalysisControllerTests の6メソッドは OS 27 未満で guard #available ... else { return }。コンパイラだけ新しくても実行 OS が古いと assertion へ到達しない。 実行 OS 27を必要条件にする。対象外ケースを明示的 skip として記録する改善を検討する。
音声統合・応答時間のテストが環境差で失敗する ExtendedAudioImportPlaybackTests は256個の WavPack を取り込み、5秒以内かつ取り込み完了前の実再生を要求する。遅い環境では期限超過、速い環境では取り込みが先に終わる可能性がある。音量0でも AVAudioEngine と iOS AVAudioSession を使用する。 低並列で実行し、音声環境と完了順序を調べる。処理の重なりを制御できる同期点を検討する。製品要件の応答期限と環境準備の待機期限を区別する。
UI の環境差・診断に時間がかかる AX snapshot、システム共有シート、画面内収まりに依存するテストがある。失敗時はスクリーンショットと結果バンドルが必要。 OS・機種・言語を記録し、.xcresult とログを失敗時にも保存する。無条件 retry で最初の失敗を消さない。
結果を待つ時間が延びる 現在の CI job 全体が約9分。全 UI/iOS 実行を追加するとさらに待つ。ローカルの未 push の変更は現在の trigger では試せない。 通常の PR 検証と長い回帰検証を分ける。手動起動の追加を検討し、開発ブランチでも試せるようにする。

根拠となるコード: テストプラン、大量一覧 UI、iOS fixture、iPhone layout、iPad layout、音楽解析、取り込み中の音声再生。

環境の保守・費用・検証範囲

Xcode 27 image はまだ Public preview で、公式告知には環境の不安定さと待ち行列の可能性が記載されている。ラベルを指定しても搭載ソフト全体が永続的に固定されるわけではない。Xcode の版・SDK・Simulator を明示し、image 更新とアプリの回帰を切り分ける。公式告知、image の管理方針。

対象リポジトリは公開であり、標準 GitHub-hosted runner の実行料金は無料。大きい runner は公開リポジトリでも有料で、Team/Enterprise Cloud の組織・enterprise 向けである。Xcode 27 の候補 xcode-27-xlarge は5 CPU・RAM 14 GB、料金は $0.102/分。標準 macOS は非公開化後の無料枠超過時に $0.062/分となる。分割 job の課金は各 runner の時間を合算する。料金、larger runner 仕様。

結果バンドルや UI の画像を増やす場合は保存量も確認する。現在の workflow は .xcresult を14日保持する。artifact の無料枠はプランに依存し、cache はリポジトリごとに10 GB の別枠。保持期間と失敗診断の必要性を両方考慮する。storage billing。hosted job の上限は6時間、Free/Pro/Team の同時 macOS job は5本なので、テスト行列を増やしすぎると待ち行列が生じる。制限。

CI に全自動テストを移しても、実機の音声出力・Bluetooth 切り替え・Music アプリの実ライブラリと AppleEvents 許可・外部ファイル提供元との操作は別の確認が必要である。現在の Music 連携テストは AppleScript のコンパイルまで。UI fixture は in-memory SwiftData とローカルの合成音源を使い、外部ファイル提供元や network を避ける。移行前から存在する検証範囲の限界であり、CI の成功から実機の動作まで保証することはできない。Music 連携のテスト、UI fixture。

推奨構成と移行時の確認

通常の PR では macOS と iOS の単体テスト、両プラットフォームのビルド、lint、変更に関係する主要 UI 操作を実行する。macOS/iPhone/iPad の全 UI 回帰は手動または定期実行の候補とする。これは構成案であり、定期実行は作成していない。ローカルでは変更箇所の小さいテストと実機確認を残す。

移行の完了条件は、全ターゲットの名前を workflow に追加することではなく、次の確認ができることである。

  1. macOS・iPhone・iPad で必要な suites が実際に走り、OS 条件で抜けるテストと skip が説明できる。
  2. 一つの runner 内の並列数を抑えた構成で、全 UI/音声統合の所要時間、ピークメモリ、空きディスクを測る。
  3. 最初の失敗と、同じ suite の単独再実行の結果を両方残す。製品の失敗、同期待ちの不備、runner の遅延をログ・結果バンドルから区別する。
  4. job/step の timeout を設定し、失敗・キャンセル時のログ保存を確認する。現在は診断2 step に10分の上限があるが、主テストと job 全体の独自上限はない。
  5. コード変更後にローカルで実行するテスト量を決める。CI を拡張しても、開発時の既定操作が全テスト実行のままなら手元の負荷は減らない。

現在のローカル資源枯渇の主因、未実行の全 UI/iOS テストの CI 所要時間・ピークメモリ・不安定な失敗の頻度は未検証である。既存 CI の成功は、これらの条件を測定した結果ではない。

関連調査: 既存 CI の待機 timeout と再確認方法。過去の失敗履歴は現行コードの未解決不具合と同一視しない。