Swift Testing の Attachment と Encodable の連携を見直す
Revise Swift Testing’s Attachment/Encodable interop
このダイジェストはClaude Opus 4.7 / 4.8によって生成されたものです(License)。原文はこちら↗。
01 何が問題だったのか
Swift Testing では、Swift 6.2 の ST-0009 で アタッチメント(attachment) が導入されました。その際、すでに Encodable や NSSecureCoding に適合している型については、Attachable プロトコルの要件のデフォルト実装が提供されました。これにより、そうした値をテストレポートやディスクに添付できます。
しかし、この当初のインターフェースにはいくつかの不便な点がありました。
- 無意味なボイラープレートが必要: すでに
EncodableやNSSecureCodingに適合している型でも、テストの作者がわざわざAttachableへの適合を明示的に書き足す必要がありました。これは型システムを満足させるだけで、実質的な意味を持たない記述です。 - エンコード形式の選び方が限られる: property list と JSON のどちらでエンコードするかを選ぶ手段が、アタッチメントの preferred name(推奨される名前)に付ける拡張子しかありませんでした。
- エンコーダの設定を変えられない: たとえば
JSONEncoder.outputFormattingを指定して整形済みの JSON を出力する、といったカスタマイズができませんでした。 - 両方に適合する型が曖昧:
EncodableとNSSecureCodingの 両方 に適合する型のエンコード方法が曖昧でした。デフォルトではEncodableを使うと文書化されていましたが、この挙動を変える手段はありませんでした。
02 どのように解決されるのか
Attachment に新しいイニシャライザを追加します。これは ST-0009 でファイル URL 向けに、ST-0023 で Transferable 適合型向けに導入されたイニシャライザと同じ流儀のものです。これらは Testing と Foundation の両方を import したファイルで利用できます。
これにより、Encodable や NSSecureCoding に適合する値を、Attachable への形式的な適合を書かずにそのまま添付できるようになります。
Encodable な値の添付
エンコード形式を AttachableEncodingFormat で指定します。
let menu = FoodTruck.currentMenu
let attachment = try Attachment(encoding: menu, as: .json)
Attachment.record(attachment)
AttachableEncodingFormat には、JSON を表す .json と、property list 形式を表す .propertyListFormat(_:) があります。
let attachment = try Attachment(encoding: recipe, as: .propertyListFormat(.binary))
Attachment.record(attachment)
エンコーダの設定を細かく調整したい場合は、エンコーダそのものを渡すイニシャライザを使います。これにより、JSONEncoder.outputFormatting のようなカスタマイズができます。
let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted]
let attachment = try Attachment(encoding: recipe, using: encoder)
Attachment.record(attachment)
エンコーダを渡すイニシャライザは、Apple プラットフォームでは Combine の TopLevelEncoder に適合するエンコーダを受け取ります。TopLevelEncoder は Combine の一部で非 Apple プラットフォームでは使えないため、非 Apple プラットフォームでは代わりに JSONEncoder / PropertyListEncoder を受け取る具体的なオーバーロードが用意されます。
NSSecureCoding な値の添付
NSSecureCoding に適合する値も、property list 形式を指定して添付できます。
let attachment = try Attachment(encoding: menu, as: .xml)
Attachment.record(attachment)
形式を省略したときの既定
エンコード形式やエンコーダを指定しなかった場合、Swift Testing はアタッチメントの preferred name(拡張子)から形式を推測します(既存のインターフェースと同じ挙動です)。preferred name も指定しなかった場合は、Encodable な型なら JSON、NSSecureCoding な型ならバイナリ property list を既定とします。
なお Encodable 向けのイニシャライザで拡張子から形式を導くときは、".xml" は XML property list、".plist" はバイナリ property list、拡張子なしや ".json" は JSON として扱われます(OpenStep 形式の property list はサポートされません)。
既存インターフェースの非推奨化
Encodable / NSSecureCoding 向けに提供されていた Attachable のデフォルト実装は、将来的な非推奨(to-be-deprecated)としてマークされます。ドキュメントには移行方法が自動的に含まれるようになりますが、ビルド時の新しい診断(deprecation warning)は将来の Swift リリースまで発行されません。
03 今後の見通し
元のProposalでは、次のような発展の方向性が挙げられています。いずれも将来の構想であり、この提案自体で実現されるものではありません。
TopLevelEncoderを標準ライブラリへ降ろす: 現在TopLevelEncoderは Combine で宣言されており、非 Apple プラットフォームでは使えません。これを標準ライブラリへ移せば、すべてのプラットフォームで同じプロトコルが使えるようになり、非 Apple プラットフォーム向けのハードコードされた回避策も取り除けます。著者はこの変更を別途提案する意向を示していますが、この提案の範囲外とされています。- 既存インターフェースの正式な非推奨化: 前述のとおり、
Encodable/NSSecureCodingとAttachableの両方に適合し、デフォルト実装に依存している型に対して、将来の Swift ツールチェインではビルド時に deprecation warning を発行する予定です。