WWDC Quick Look 💓 By SwiftGGTeam
Triage test failures with XCTIssue

Triage test failures with XCTIssue

元の動画を見る

ハイライト

Xcode 12 は XCTest の失敗を次のようにラップしますXCTIssue、タイプ、詳細な説明、根本的なエラー、添付ファイル、コール スタックを失敗に伝えることができ、開発者は Issue Navigator とテスト レポートでトリガー パスを追跡できます。

主要内容

テスト スイートの維持で最も時間がかかる部分は、多くの場合、テストが失敗した後に発生します。ローカルまたは CI で障害が発生した場合、開発者は 4 つの質問に答える必要があります。それは、どこで障害が発生したか、どのように障害が発生したのか、なぜ障害が発生したのか、障害がトリガーされたテスト コードの行はどれなのかということです。 Xcode 12 では、これらの問題が同じトラブルシューティング パスに組み込まれます。

スピーチの例は、PlayGarden と呼ばれる小さなプロジェクトからのものです。重複を減らすために、テスト コードは共有ユーティリティ関数に抽出されました。問題も発生します。失敗マークがヘルパーに含まれる場合、テスト メソッド自体には灰色のマークが表示されるだけであり、開発者はコンテキストを見つけるために呼び出し関係に従う必要があります。

Xcode 12 の変更は、失敗、ソースコードの場所、および呼び出しスタックをまとめて表示することです。 Issue Navigator はテスト コード内のコール スタックを拡張できます。テスト レポートは同じフレームのグループを表示することもでき、ジャンプ ボタンまたはアシスタント ボタンを使用してレポートとソース コードを並べて開くことができます。 CI からの結果バンドルの場合、これにより、ローカル レプリケーション前のブラインド チェック時間を短縮できます。

基盤となる API も調整されました。 XCTest は、メッセージ、ファイル パス、行番号、および失敗が予期されていたかどうかという 4 つの個別の値を使用して失敗をログに記録していました。 Xcode 12の場合XCTIssueこのデータをラップし、タイプ、詳細な説明、根本的なエラー、および添付ファイルを追加します。カスタム アサーション、障害観察、障害フィルタリング、および診断添付ファイルはすべて、同じオブジェクトに関して完了できます。

詳細

Swift エラースロー テストにはソース コードの場所があります

(04:21) XCTest はテスト機能を直接サポートしますthrow。テストでエラーがスローされると、そのエラーは失敗メッセージを形成します。 Xcode 12 には、このタイプのエラーのソース コードの場所を報告するための Swift ランタイム、iOS および tvOS 13.4、macOS 10.15.4 の改善が組み込まれています。

(05:15) 同じ便利なセットがライフサイクル メソッドにも組み込まれています。setUpWithError()オリジナルではsetUp()前に走って、tearDownWithError()オリジナルではtearDown()後で走ってください。新しいテスト ファイル テンプレートにはこれらのメソッドが含まれます。多くの場合、継承構造が依然として古いメソッドに依存しているため、古いメソッドは依然として保持されます。

### 使用XCTIssueカスタム アサーションを作成する

(09:52) カスタム アサーションを直接作成できますXCTIssue、障害の説明、添付ファイル、呼び出し場所を同じオブジェクトに書き込み、それを次のオブジェクトに渡します。record(_:)

func assertSomething(about data: Data,
                         file: StaticString = #filePath,
                         line: UInt = #line) {

        // Call out to custom validation function.
        if !isValid(data) {

            // Create issue, declare with var for mutability.
            var issue = XCTIssue(type: .assertionFailure, compactDescription: "Invalid data")

            // Attach the invalid data.
            issue.add(XCTAttachment(data: data))

            // Capture the call site location as the point of failure.
            let location = XCTSourceCodeLocation(filePath: file, lineNumber: line)
            issue.sourceCodeContext = XCTSourceCodeContext(location: location)

            // Record the issue.
            self.record(issue)
        }
    }

キーポイント:

  • var issue後続の変更を許可するXCTIssue
  • XCTIssue(type:compactDescription:)障害の種類と簡単な説明を記録します。
  • issue.add(XCTAttachment(data: data))失敗データをテストレポートに添付します。
  • XCTSourceCodeLocation呼び出し元から渡された値を使用しますfileそしてline、カスタム アサーションが呼び出された場所をレポートが指すようにします。
  • self.record(issue)問題を XCTest と Xcode に報告します。

テストクラスの失敗を観察する

11:12record(_:)それは、テストクラスのすべての失敗者が通過する入り口です。これをオーバーライドすると、クラス スコープ内の障害を観察して、XCTest に進むことができます。

override func record(_ issue: XCTIssue) {

    // Observe, introspect, log, etc.:
    if shouldLog(issue) {
        print("I just observed an issue!")
    }

    // Don't forget to call super!
    super.record(issue)
}

キーポイント:

  • override func record(_ issue: XCTIssue)現在のテスト クラスに障害記録プロセスを引き継がせます。
  • shouldLog(issue)ローカルの観測またはログの状態を表します。
  • super.record(issue)呼び出す必要があります。呼び出されないと、問題はレコード チェーンに継続されません。
  • 特定のテスト クラスの失敗だけを観察したい場合、この方法はグローバルな観察よりもローカルな方法です。

条件による失敗の抑制

(11:30)record(_:)それ以降は電話しないでくださいsuperこれにより、問題が記録されたり報告されたりすることがなくなります。

override func record(_ issue: XCTIssue) {

    // If you don't want to record it, just return.
    if shouldSuppress(issue) {
        return
    }

    // Otherwise pass it to super.
    super.record(issue)
}

キーポイント:

  • shouldSuppress(issue)現在の障害をフィルタリングする必要があるかどうかを決定します。
  • return記録プロセスは終了し、Xcode はこの問題を受け取りません。
  • フィルタリングされていない失敗も引き続き呼び出されますsuper.record(issue)
  • このタイプのロジックは、実際に修正する必要がある問題が隠れることを避けるために、明確な境界を持つテスト クラスに配置するのに適しています。

診断添付ファイルを障害に追加する

(11:39) 問題を修正してカバーしますrecord(_:)一般的な用途。まずパラメータを次のように再宣言します。var、次に添付ファイルを追加し、最後にそれを渡しますsuper

override func record(_ issue: XCTIssue) {

    // Redeclare using var to enable mutation.
    var issue = issue

    // Add a simple attachment.
    issue.add(XCTAttachment(string: "hello"))

    // Pass it to super.
    super.record(issue)
}

キーポイント:

  • var issue = issue渡されたオブジェクトを変更可能なコピーに変換します。
  • issue.add(XCTAttachment(string: "hello"))失敗に文字列添付ファイルを追加する方法を示します。
  • トランスクリプトには、Attachment API がカスタム診断データの保存に使用できる複数のタイプをサポートしていると記載されています。
  • 変更完了後に呼び出されますsuper.record(issue)、拡張された問題を Xcode テスト レポートに表示させます。

コールスタックにより、共有ヘルパーのエラーが明確になります

(08:28) 共有ヘルパーに複数のアサーションがある場合、呼び出し場所を 1 つだけ渡すとあいまいさが残ります。XCTIssueコール スタックをキャプチャしてシンボル表示した後、テスト メソッドは灰色のマークを表示し、実際に失敗したヘルパー行は赤色のマークを表示し、問題ナビゲータとテスト レポートの両方がフレームに沿ってジャンプできます。

大規模なテスト スイートの場合、これは簡単です。開発者は、障害を特定するためにテスト構造を犠牲にすることなく、再利用された関数を抽出し続けることができます。障害レポートにはトリガー パスが保持されるため、トラブルシューティング中にテストの入り口から実際のアサーションに進むことができます。

重要ポイント

  • データ検証専用のアサーションを作成します: 対処方法: 重複を削除しますisValid(data)チェックはテスト ヘルパーとしてパッケージ化されています。実行する価値がある理由:XCTIssue障害の説明、データの添付ファイル、通話場所を同じ障害レコードに含める機能。開始方法: 公式スニペットから作成するvar issue = XCTIssue(type: .assertionFailure, compactDescription: ...)、に追加XCTAttachment(data:)、その後電話しますrecord(_:)
  • 失敗に診断テキストを自動的に添付します: 対処方法: テスト クラスでオーバーライドします。record(_:)、各失敗のコンテキストを追加します。実行する価値がある理由: テスト レポートには追加の添付ファイルが付属し、CI 結果バンドルは直接読みやすくなります。開始方法: 受信した問題を次のようにコピーしますvar、 電話issue.add(XCTAttachment(string: ...))、最後に電話しますsuper.record(issue)
  • いくつかのテスト クラスの失敗ログを追加します: 対処方法: テスト バンドル全体に影響を与えず、1 つのテスト クラスでの失敗のみを観察します。なぜそれを行う価値があるのか​​: スピーチが指摘するrecord(_:)故障プロセスの入り口となるため、局所的な観察や記録に適しています。開始方法: 対象範囲record(_:)、存在するshouldLog(issue)状況に応じて情報を記録し、電話をかけ続けます。super.record(issue)
  • エラーをスローするセットアップとティアダウンの移行: 対処方法: エラーをスローする必要がある準備およびクリーンアップ ロジックを次の場所に移動します。setUpWithError()tearDownWithError()。実行する価値がある理由: Xcode 12 では、スローされたエラーのソース コードの場所がレポートされるため、手書きのエラー処理の定型文が削減されます。開始方法: 継承要件を処理するために古いメソッドを保持し、新しいテストでは最初にそれを使用します。Errorライフサイクルメソッド。
  • 引き続き再利用できるように共有テスト ツールを有効にする: 対処方法: 重複したアサーションをヘルパーに残し、Xcode 12 の失敗したコール スタックの場所のパスに依存します。実行する価値がある理由: このトークでは、灰色のエントリ マーカーと赤色の実際の失敗マーカーが表示され、トリガーと失敗の両方が示されます。開始方法: 失敗したテストを実行し、問題ナビゲーターまたはテスト レポートのコール スタックに沿ってフレームを検査します。

関連セッション

コメント

GitHub Issues · utterances