WWDC Quick Look 💓 By SwiftGGTeam
Embrace Expected Failures in XCTest

Embrace Expected Failures in XCTest

元の動画を見る

ハイライト

Apple は、XCTest で XCTExpectFailure を提供しています。これにより、既知のテストの失敗を継続し、レポートで予想される失敗としてマークされるため、ノイズが軽減され、新しい問題の兆候が維持されます。

主要内容

昨日合格していたテストが今日不合格になりました。最初の失敗には価値がある。これは、製品にバグがあることを示している場合もあれば、テストが正しく記述されていないことを示している場合もあり、依存するフレームワークやシステムの動作が変更されたことを示している場合もあります。

問題は、チームがすぐに問題を解決できるとは限らないということです。後続の各 CI 実行では、引き続き同じ失敗が報告されます。赤の結果はまだ残っていますが、新しい情報は提供されなくなりました。本当の新しい失敗は古い失敗の中に埋もれてしまいます。

以前は 2 つの一般的な処理方法がありました。 1 つ目は、テスト計画またはスキームでテストを無効にすることです。コードは引き続きコンパイルされますが、テストは実行されず、問題はレポートに表示されません。 2 つ目は、XCTSkip を使用することです。テストはスキップ ポイントまで実行され、レポートに記録されますが、スキップ ポイント以降のコードは実行されず、それ以降の情報は失われます。

このセッションで Apple が紹介したツールは XCTExpectFailure です。登録済みで当面修理できない障害への対応に適しています。テストは通常​​どおり実行され、ヒットの失敗は予期された失敗として報告され、それを含むテスト スイートは合格の混合ステータスを示します。引き続き問題を確認し、新しい障害をより早く発見できます。

既知の障害は依然として欠陥に関連付けられる必要があります

XCTExpectFailure は失敗の理由を受け入れます。講演では、バグ追跡システムの URL をこの文字列に入れることが提案されました。 Xcode のテスト レポートは URL を認識し、マウスを移動するとジャンプ ボタンを表示して、テスト レポートから問題の記録に戻りやすくします。

スコープが小さいほどノイズは少なくなります

XCTExpectFailure には 2 つの用途があります。ステートフルな使用は、呼び出し後の失敗に影響します。スコープ付き使用では、失敗する可能性のあるコードがクロージャにラップされ、クロージャの外側の失敗は通常どおり報告されます。外部のテスト状態への影響が軽減されるため、共有テスト ツール関数でスコープ指定された記述方法を使用する方が適しています。

Strict モードは期限切れのタグを削除するのに役立ちます

デフォルトの動作は厳密です。予期された障害を宣言したが、今回は障害がなかった場合、XCTest は不一致の予期された障害と呼ばれる新しい障害を生成します。これにより、根本的な問題が修正された可能性があるため、XCTExpectFailure を削除する必要があるという警告が表示されます。

不安定なテストの場合、厳密モードでは追加のノイズが発生します。 XCTExpectedFailure.Options は、オフにできる isStrict を提供します。 Swift バージョンでは、XCTExpectFailure で strict: false を直接渡すこともサポートされています。

詳細

1. XCTSkip を使用して制限を構成する

(03:31) XCTSkip は、構成の制約を表現するのに適しています。講演の例では、テストは iPad のみをサポートしています。テストはこの行まで実行され、デバイスが iPad でない場合はスキップされます。

try XCTSkipUnless(UIDevice.current.userInterfaceIdiom == .pad, "Only supported on iPad")

キーポイント:

  • tryXCTSkipUnlessスキップ例外がスローされるため、テスト メソッドはそれを処理する必要があります。
  • XCTSkipUnless(...): 条件が false の場合、現在のテストをスキップします。
  • UIDevice.current.userInterfaceIdiom == .pad:テスト実行環境をiPadに限定します。
  • "Only supported on iPad": テストレポートにスキップ理由を記述します。

この API は環境の不一致を解決します。スキップポイント以降のテストコードは実行を継続しないため、既知の障害の処理には適していません。

2. 既知の障害を XCTExpectFailure でマークする

(04:31) XCTExpectFailure は、登録された障害を管理するために使用されます。呼び出し後、テストは実行を継続し、ヒットの失敗は予期された失敗として表示されます。

XCTExpectFailure("<https://dev.myco.com/bugs/4923> myValidationFunction is returning false")

キーポイント:

  • XCTExpectFailure(...): 現在のテストの次の失敗が既知の失敗であることを宣言します。
  • "<https://dev.myco.com/bugs/4923> ...": 失敗の理由にはバグ リンクが含まれており、Xcode レポートは問題追跡システムにジャンプできます。
  • myValidationFunction is returning false: 理由テキストは、コンテキストフリーのマークのみが残ることを避けるために、特定の障害点を説明します。

講義では、この行を追加すると、失敗したテストの赤い X が灰色の X に変わります。これを含むテスト スイートは緑のダッシュに変わり、合格したがスキップまたは予想される失敗が含まれていることを示します。

3. 影響範囲を限定するために範囲指定された書き込みを使用する

(07:14) 特定の行だけが既知のエラーを引き起こす場合は、それらの行をクロージャに入れます。クロージャの外側で障害が発生した場合でも、XCTest はそれを通常の障害として処理します。

XCTExpectFailure("<https://dev.myco.com/bugs/4923> fix myValidationFunction") {
    XCTAssert(myValidationFunction())
}

キーポイント:

  • XCTExpectFailure(... ) { ... }: クロージャ内のコードのみをカバーする予想される失敗スコープを作成します。
  • "<https://dev.myco.com/bugs/4923> fix myValidationFunction": 問題のリンクと修正ターゲットをログに記録します。
  • XCTAssert(myValidationFunction()): 真のアサーションは引き続き実行され、失敗時にクロージャ スコープによってキャプチャされます。
  • クロージャの外側のコード: 障害が発生した場合、通常の障害として報告されます。

この講演では、XCTExpectFailure がネストをサポートしていることも説明されています。失敗すると、最初に最も近い呼び出しポイントと一致し、次にマッチャーが拒否した場合は外部呼び出しに渡されます。共有テスト ライブラリでクロージャ書き込みを使用すると、呼び出し側のテストへの影響を軽減できます。

4. issueMatcher を使用して障害タイプを正確に照合する

(08:34) デフォルトでは、スコープ内の障害はすべて捕捉されます。新しい問題を発見するには、オプションに issueMatcher を設定し、条件を満たす XCTIssue のみを受け入れることができます。

let options = XCTExpectedFailure.Options()
options.issueMatcher = { issue in
    return issue.type == .assertionFailure
}

XCTExpectFailure("<https://dev.myco.com/bugs/4923> fix myValidationFunction", options: options)

キーポイント:

  • let options = XCTExpectedFailure.Options():予想される障害構成オブジェクトを作成します。
  • options.issueMatcher = { issue in ... }: 構成オブジェクトの失敗マッチャーを設定します。
  • issue:XCTest が渡されましたXCTIssue、失敗の詳細が含まれています。
  • return issue.type == .assertionFailure: アサーションの失敗を予期された失敗としてのみ扱います。
  • XCTExpectFailure(..., options: options): 一致ルールを予想される失敗ステートメントに渡します。

マッチャーが失敗を拒否した場合、その失敗は予期された失敗として扱われません。このようにして、古い質問はノイズを軽減し続けますが、新しい質問は依然としてテストを赤点にする可能性があります。

5. プラットフォームごとに予想される失敗をクローズする

(09:03) 一部の障害は、特定のプラットフォームでのみ発生します。講演で挙げられた例は、macOS ではテストが成功するが、iOS ではテストが失敗するというものです。一部のプラットフォームでの予期される失敗アサーションは、options.isEnabled を介してオフにできます。

let options = XCTExpectedFailure.Options()
#if os(macOS)
options.isEnabled = false
#endif

XCTExpectFailure("<https://dev.myco.com/bugs/4923> fix myValidationFunction", options: options) {
    XCTAssert(myValidationFunction())
}

キーポイント:

  • let options = XCTExpectedFailure.Options(): 設定オブジェクトを準備します。
  • #if os(macOS): macOS ビルド ブランチ内でのみ構成を実行します。
  • options.isEnabled = false: macOS では、この予期される失敗ステートメントをオフにします。
  • #endif: プラットフォームの条件付きコンパイルを終了します。
  • XCTExpectFailure(..., options: options) { ... }: 設定を使用してクロージャ内でアサーションを実行します。
  • XCTAssert(myValidationFunction()):失敗は、予想される失敗が有効になっているプラ​​ットフォームでのみ検出されます。

この書き方は、プラットフォーム、デバイスの種類、システムのバージョンの違いなど、決定的な環境の違いに適しています。

6. 不安定なテストの厳密な動作をオフにする

(10:39) XCTExpectFailure のデフォルトは strict です。 XCTest は、予期される障害が宣言されたものの捕捉されなかった場合、一致しない予期された障害を報告します。この動作は、期限切れのタグを削除するよう求めるため、安定した障害に適しています。

let options = XCTExpectedFailure.Options()
options.isStrict = false

XCTExpectFailure("<https://dev.myco.com/bugs/4923> fix myValidationFunction", options: options) {
    XCTAssert(myValidationFunction())
}

キーポイント:

  • let options = XCTExpectedFailure.Options():設定オブジェクトを作成します。
  • options.isStrict = false: 厳密な動作をオフにします。
  • XCTExpectFailure(..., options: options) { ... }: 予期される障害スコープを非厳密な構成で実行します。
  • XCTAssert(myValidationFunction()): 今回アサーションが合格しても、テストは引き続き合格します。

Swift ではパラメータを直接書き込むこともできます。

XCTExpectFailure("<https://dev.myco.com/bugs/4923> fix myValidationFunction", strict: false) {
    XCTAssert(myValidationFunction())
}

キーポイント:

  • strict: false: オプションを個別に作成せずに、厳密な動作を直接オフにします。
  • クロージャ内部アサーション: 失敗は期待どおりに処理され、パスされた場合に一致しない期待された失敗は生成されません。

この講演では、タイミングの問題、順序付けの依存関係、同時実行性のバグなど、非決定的な障害シナリオでこの使用法が取り上げられています。

重要ポイント

  • 何をすべきか: 既知の失敗したテストのそれぞれにバグ リンクを追加します。 実行する価値がある理由: XCTExpectFailure の理由には URL を含めることができ、Xcode テスト レポートは予想される失敗から問題のあるシステムに戻ることができます。 開始方法: 失敗したテストの一時的なコメントを次のように変更します。XCTExpectFailure("<bug URL> 失败原因")

  • 内容: 共有テスト ツール機能の既知の障害を範囲指定に変更します。 実行する価値がある理由: クロージャ スコープは内部の障害のみを捕捉し、外部のテストでの新しい障害は引き続き赤で表示されます。 開始方法: を使用しますXCTExpectFailure("原因") { ... }既知の失敗したアサーションをラップします。

  • 何をすべきか: 不安定なテストに対して、厳密には予期されない失敗リストを作成します。 実行する価値がある理由:isStrict = false偶然通りかかったときに予期せぬ失敗を避けてください。 開始方法: 関連するテストを作成するXCTExpectedFailure.Options()、設定options.isStrict = false、そしてそれを渡しますXCTExpectFailure

  • 内容: 特定の障害タイプのみを予期される障害としてマークします。 実行する価値がある理由:issueMatcherフィルタリング可能XCTIssue、古いアサーション障害のノイズは除去されますが、新しいクラッシュやその他の障害は引き続き露出されます。 開始方法: セットアップoptions.issueMatcher、から始めますissue.type == .assertionFailureそんなルールが始まります。

  • 何をすべきか: 予想される障害戦略をプラットフォームごとに分割します。 実行する価値がある理由: スピーチの中でoptions.isEnabled一部のプラットフォームで予期されるエラーをオフにすることをサポートし、iOS で失敗し、macOS で修正されたテストに適しています。 開始方法: を使用します#if os(macOS)またはその他のプラットフォーム条件設定options.isEnabled = false

関連セッション

コメント

GitHub Issues · utterances