WWDC Quick Look 💓 By SwiftGGTeam
Author fast and reliable tests for Xcode Cloud

Author fast and reliable tests for Xcode Cloud

元の動画を見る

ハイライト

Xcode Cloud は、複数のプラットフォームおよび複数のシステム バージョンでのテスト スイートの並列実行をサポートしていますが、テスト量が拡大すると、信頼性の低いテストが CI プロセスに影響を及ぼします。Apple はXCTSkipXCTExpectFailure、テストの繰り返し実行、並列テスト、およびタイムアウト制御メカニズムを通じて、開発者が信頼性と高速性の両方を備えたテストを作成できるようにします。

主要内容

テスト環境は信頼できませんか?セットアップから始める

テストをローカルで実行するとすべて正常に動作しますが、CI でテストを実行すると失敗します。問題は、Xcode Cloud が新しいシミュレーターを使用しており、タイムゾーン、ロケール、ネットワーク権限、およびプリセットデータがローカルのものと異なる可能性があることです。

Apple の提案は次のとおりです。すべての州の準備をsetUp()ここじゃなくてここtearDown()次のテストに備えてクリーンアップをします。各テストは、それぞれの初期状態を独立して担当します。

03:37

条件が満たされない場合、テストをスキップします。

一部のテストは特定の環境でのみ実行されます。たとえば、運用環境の注文インターフェイスを実際に呼び出すことはできません。そうしないと、実際の注文が生成されます。XCTSkip実行時に条件をチェックし、テストをスキップできます。

06:00

既知の失敗したテスト。ミュートしないでください

外部サービスのメンテナンス中は、関連するテストが失敗します。テストを直接無効にするとカバレッジが失われます。XCTExpectFailure失敗は「予想される失敗」としてマークでき、問題を追跡しながらテスト スイート全体は合格します。

10:02

並列テストの高速化 CI

Xcode Cloud はデフォルトで複数のプラットフォームを並行してテストします。テスト計画で「並列実行」を有効にして、複数のテスト ターゲットとテスト クラスをサーバーのマルチコアで同時に実行できるようにすることもできます。

16:37

テストの暴走によるスイート全体のダウンを防ぐ

テストが無限ループに陥ったり、タイムアウトを待ったりすると、CI プロセス全体が停止します。テスト計画の構成で「テスト タイムアウト」をオンにし、単一テストの最大実行時間を設定します (デフォルトは 600 秒)。タイムアウトにより自動的に失敗がマークされ、後続のテストの実行が続行されます。

17:52

詳細

async setUp を使用してテスト データを準備する

var truck: Truck!

override func setUp() async throws {
    let directoryURL = FileManager.default.temporaryDirectory
    let fileName = UUID().uuidString
    let fileURL = directoryURL.appendingPathComponent(fileName, isDirectory: false)
    let data = await mockDonutMenuData()
    try data.write(to: fileURL)
    truck = Truck(menuURL: fileURL)
}

キーポイント:

  • setUp()としてマークされていますasync throws、非同期データ準備とエラースローをサポートします。
  • temporaryDirectoryを使用して、実ファイルシステムを汚染しないようにします
  • UUID().uuidString並列テスト間の競合を避けるために、各テストで個別のファイル名が使用されていることを確認します。
  • 存在するsetUp()ですべての状態の初期化を完了します。tearDown()掃除

環境変数を使用してテスト プロセスを制御する

var truck: Truck!

func testOrderDonut() throws {
    let host = ProcessInfo.processInfo.environment["BASE_URL"]
    try XCTSkipIf(host == "prod.example.com")

    let expectation = XCTestExpectation(description: "Order donut")
    truck.order(with: .sprinkles, host: host) { error, donut in
        XCTAssertTrue(donut.hasSprinkles)
        expectation.fulfill()
    }
    wait(for: [expectation], timeout: 5)
}

キーポイント:

  • ProcessInfo.processInfo.environment環境変数を読み取る
  • XCTSkipIf条件が満たされた場合にテストをスキップし、スキップ済みとしてマークされます。
  • Xcode Cloudに環境変数を追加する必要がありますTEST_RUNNER_プレフィックスなどTEST_RUNNER_BASE_URL、ランタイムプレフィックスは自動的に削除されます
  • テスト計画で環境変数を構成するときにプレフィックスは必要ありません

期待タイムアウトの代わりに async/await を使用する

func testOrderDonut() async throws {
    let host = ProcessInfo.processInfo.environment["BASE_URL"]
    try XCTSkipIf(host == "prod.example.com")

    let donut = try await truck.orderDonut(with: .sprinkles, host: host)
    XCTAssertTrue(donut.hasSprinkles)
}

キーポイント:

  • テスト方法は次のようにマークされています。async throws、非同期 API を直接呼び出します
  • もう必要ありませんXCTestExpectationそしてwait(for:timeout:)
  • タイムアウト制限はありません。テストは非同期操作が完了するまで待機します。
  • コードがより簡潔になり、遅いサーバーによって引き起こされるタイムアウト障害が回避されます。

予想される失敗をマークします

func testOrderDonut() async throws {
    let host = ProcessInfo.processInfo.environment["BASE_URL"]
    try XCTSkipIf(host == "prod.example.com")

    XCTExpectFailure("https://dev.myco.com/bug/98 Donut ordering service is down")
    let donut = try await truck.orderDonut(with: .sprinkles, host: host)
    XCTAssertTrue(donut.hasSprinkles)
}

キーポイント:

  • XCTExpectFailure説明文字列 (通常はバグリンク) を受け取ります
  • ラップされたアサーションの失敗は「予期された失敗」として記録されます。
  • CI の結果を妨げる既知の問題を避けるため、テスト スイート全体は引き続き合格とみなされます。
  • サービスが復旧すると、テストは自動的に通常の合格ステータスに戻ります。

プル リクエスト専用のテスト プランを構成する

// Test Plan の Tests タブでサブセットを選択
// 例:単体テスト + 重要な UI テストだけを選ぶ

キーポイント:

  • コアテストのみを含む専用の「プルリクエスト」テスト計画を作成します。
  • Xcodeクラウドワークフローで開始条件を「Pull Request Changes」に設定します
  • ビルド アクションとテスト アクションを追加し、プル リクエストのテスト プランを選択します
  • スケジュールされた別のワークフローを作成して、完全なテスト スイートを実行します

重要ポイント

  • さまざまな環境向けに階層化されたテスト計画を作成: コア テストは PR で迅速に検証され、完全なテストはバックグラウンドで実行されるようにスケジュールされます。入り口: Xcode -> 製品 -> テスト計画 -> 新規、Xcode クラウド -> ワークフローの管理。

  • 環境変数を使用してテスト動作を制御: Xcode クラウド ワークフローまたはテスト計画で構成しますTEST_RUNNER_*テストコードで渡される環境変数ProcessInfo一連のテスト コードを読み取って実装し、複数の開発/テスト/運用環境に適応させます。

  • 非同期テストを async/await に移行します: に基づきますXCTestExpectationコールバック テストは次のように書き換えられます。async throwsテスト方法、タイムアウト パラメーターを排除し、ネットワークの変動によって引き起こされる不安定なテストを削減します。

  • 既知の問題には XCTExpectFailure を使用します: 外部依存関係が原因で失敗するテストを無効にしたりスキップしたりせず、使用します。XCTExpectFailureテスト カバレッジを保存し、問題が修正されたときに自動的に復元するパッケージ。

  • CI のスタックを防ぐために単一のテスト タイムアウトを設定します: 単一の制御不能なテストが CI プロセス全体に影響を与えるのを防ぐために、[テスト計画] -> [構成] -> [テスト タイムアウト] で適切な実行時間制限を設定します。

関連セッション

コメント

GitHub Issues · utterances