プロトコルベースのSwift依存性注入テスト
外部の依存関係(ファイルシステム、ネットワーク、iCloud)を小さく焦点を絞ったプロトコルとして抽象化することで、SwiftコードをテストしやすくするパターンI/Oなしの決定論的テストをサポートする。
起動条件
- ファイルシステム、ネットワーク、または外部APIにアクセスするSwiftコードを書く場合
- 実際の障害を起こさずにエラー処理パスをテストする必要がある場合
- 異なる環境(アプリ、テスト、SwiftUIプレビュー)で動作するモジュールを構築する場合
- Swift並行処理(Actor、Sendable)をサポートするテスト可能なアーキテクチャを設計する場合
コアパターン
1. 小さく焦点を絞ったプロトコルを定義する
各プロトコルは1つの外部関心事のみを処理する。
// File system access
public protocol FileSystemProviding: Sendable {
func containerURL(for purpose: Purpose) -> URL?
}
// File read/write operations
public protocol FileAccessorProviding: Sendable {
func read(from url: URL) throws -> Data
func write(_ data: Data, to url: URL) throws
func fileExists(at url: URL) -> Bool
}
// Bookmark storage (e.g., for sandboxed apps)
public protocol BookmarkStorageProviding: Sendable {
func saveBookmark(_ data: Data, for key: String) throws
func loadBookmark(for key: String) throws -> Data?
}
2. デフォルト(本番用)実装を作成する
public struct DefaultFileSystemProvider: FileSystemProviding {
public init() {}
public func containerURL(for purpose: Purpose) -> URL? {
FileManager.default.url(forUbiquityContainerIdentifi…