test issue の severity
Test Issue Severity
このダイジェストはClaude Opus 4.7 / 4.8によって生成されたものです(License)。原文はこちら↗。
01 何が問題だったのか
Swift Testing でテストの実行中に問題が起きた場合、その情報は issue として記録されます。#expect の失敗や Issue.record(...) で残されるものがこれに当たり、これまでは issue を記録すると 必ずテストが失敗扱い になりました。
しかし、テストの実行中に観測した出来事の中には、「失敗とまでは言えないが結果に残しておきたい」というものもあります。
- スナップショットテストで画像を比較する際、90% 以上の一致を合格とした上で、95% に満たない場合は「同一ではない」ことに気づけるよう知らせたい
- ライブラリのテスト用 API に同じ引数が複数回渡されたとき、利用者の意図がある場合に備えてエラーにはせず注意だけ促したい
- 統合テストで一次サーバが落ちていて代替サーバに切り替わった、といった 回復可能な想定外の挙動 を結果に残したい
- テストのセットアップ中に行ったリトライが成功した場合に、リトライがあったこと自体は記録しておきたい
これらはいずれも、テストを失敗させずに結果に残すべき情報です。issue がすべて失敗を意味するという従来の前提のままでは、こうした情報を表現する手段がなく、テストの実行結果から得られる洞察が限られていました。
02 どのように解決されるのか
issue に severity(重要度) という概念を導入し、error と warning の 2 段階で表せるようにします。error の issue は従来通りテストを失敗させますが、warning の issue はテストを失敗させず、結果に「警告として記録された」情報として残ります。
Issue.Severity
severity は Issue のネスト型 Issue.Severity として定義されます。Comparable に適合しており、warning < error の順序を持ちます。
extension Issue {
public enum Severity: Codable, Comparable, CustomStringConvertible, Sendable {
case warning
case error
}
}
warning として issue を記録する
Issue.record(...) に severity: パラメータが追加され、.warning を渡すことで失敗扱いにならない issue を記録できます。デフォルトは .error で、これまでの呼び出しと同じ挙動になります。
Issue.record("My comment", severity: .warning)
メソッドのシグネチャは次の通りです。
extension Issue {
@discardableResult
public static func record(
_ comment: Comment? = nil,
severity: Severity = .error,
sourceLocation: SourceLocation = #_sourceLocation
) -> Self
}
なお、既存の severity: を持たない Issue.record(_:sourceLocation:) も、関数値として参照しているコードを壊さないために残されますが、deprecated 扱いとなり新しい API の利用が推奨されます。
Issue の severity と isFailure
Issue には新しく 2 つのプロパティが加わります。
severity: その issue の severity を取得・設定できるプロパティisFailure: その issue がテストの失敗とみなされるかを表すBoolの computed property
extension Issue {
public var severity: Severity { get set }
public var isFailure: Bool { get }
}
isFailure は、severity が .error 以上で、かつ withKnownIssue(...) で「既知の issue」として扱われていない場合に true になります。「失敗かどうか」を判定したいときは、severity を直接比較するのではなく isFailure を使うことが推奨されます。これは将来 severity の段階が増えても、isFailure を見ているコードはそのまま動き続けるようにするためです。
isFailure と severity は、たとえば withKnownIssue のマッチング条件で次のように組み合わせて使えます。
withKnownIssue {
// ...
} matching: { issue in
issue.isFailure || issue.severity > .warning
}
コンソール出力
.warning の issue が記録されたテストは、失敗せずに合格として扱われ、警告が記録された旨が出力に含まれます。
◇ Test "All elements of two ranges are equal" started.
⚠ Test "All elements of two ranges are equal" recorded a warning at ZipTests.swift:32:17: Issue recorded
↳ My comment
✔ Test "All elements of two ranges are equal" passed after 0.001 seconds with 1 warning.
イベントストリームとの連携
JSON 形式のイベントストリームにも severity と isFailure が反映されます。issueRecorded イベントの issue オブジェクトに severity と isFailure の 2 つのフィールドが追加されます。
<issue> ::= {
"isKnown": <bool>,
+ "severity": <string>,
+ "isFailure": <bool>,
["sourceLocation": <source-location>,]
}
これは「すべての issueRecorded は失敗を意味する」と仮定していたツールにとっては破壊的変更にあたるため、イベントストリームのバージョンが上がります。従来通りの v1 では挙動を維持し、.warning の issue については issueRecorded イベントを出力しません。新しいバージョンを利用するツールは、isFailure を見て失敗かどうかを判定することになります。
03 今後の見通し
将来の発展として、以下のようなアイデアが挙げられています。
- 警告として記録された issue を、より厳しいテスト構成のもとでエラーに 昇格 させ、警告も失敗扱いとして実行できるようにする
infoやdebugといった、warningよりさらに弱いレベルの severity を追加し、ユーザーが結果に残したい情報をより細かく分類できるようにする
これらはいずれも将来の構想であり、実現を約束するものではありません。