目次
Session概要
Xcodeでの最新のTesting APIを用いてキャッチされていない問題をトリアージし、分析する方法について。テストワークフローを簡単にする方法、テストでの失敗をコンテキストに組み込む方法について。
Xcode12で追加されたテスト失敗時のレポートUIを拡張した内容について https://developer.apple.com/videos/play/wwdc2020/10687/
Xcode12でのXCTest失敗時のUI
- 失敗した前のコードにて注釈コメントを表示
- Issue Navigator でテストコードのコールスタックが確認可能
- コールスタックの行をクリックするとコードにジャンプ
- コールスタックの行をクリックするとコードにジャンプ


上記はTestレポート画面でコールスタックからコードへジャンプしたり、アシスタントボタンから対象コードを2分割で表示することが可能
Swift Errors in Tests
Swiftランタイムの改良により、iOS13.4, macOS10.15.4からthrowされたエラーと対象のソースコードの位置がわかるようになったため、エラーのコンテキストを把握することが容易になった。

Xcode12より、
setupWithError
, tearDownWithError
が追加された
リッチな失敗オブジェクト
XCTestは失敗を4つの値に分類する
- 失敗メッセージ
- ファイルパス
- 失敗が記録された行番号
- 失敗の予想を示すフラグ
予想された失敗はXCTAssertに表示される。
予期せぬ失敗はthrowされた例外をXCTestが捉えること。
失敗したデータはXCTAssertから
recordFailure
APIに渡され、失敗を記録してXcodeに伝えられていた。Xcode12では、
XCTIssue
で↑の4つを保持し追加で、明示型タイプの計算方
、詳細な記述
, 内在するエラー
, 添付
がある。
XCTAttachment
XCTAttachmentは任意のデータをキャプチャするAPIで、テスト自体もしくは、XCTContextによるアクティビティに添付する。
XCTIssueにも紐付け可能。
XCTestCaseの新しいAPI
失敗を記録するためのAPI
直接呼び出しやオーバーライド可能

XCTIssue
コールスタックをキャプチャしシンボル化出来る。そのため、複雑なテストコードの失敗に対するコンテキストが増える。
例えば、下記のテストコードでは失敗した箇所と、どこのコードで失敗したかを明確に把握することが出来る

XCTIssueを用いたカスタムTestアサーション
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)
}
}
override func record(_ issue: XCTIssue) {
// 特定の条件で記録する
if shouldLog(issue) {
print("I just observed an issue!")
}
// If you don't want to record it, just return.
// 特定の条件で何も記録しない
if shouldSuppress(issue) {
return
}
// Otherwise pass it to super.
super.record(issue)
}
XCTAttachment
を付与することで失敗の診断および分析に役立つ
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)
}