Makes Swift code testable by abstracting file system, network, and iCloud dependencies behind focused protocols. Provides mock implementations for deterministic testing without I/O.
How this skill is triggered — by the user, by Claude, or both
Slash command
/everything-claude-code:swift-protocol-di-testingThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
通过将外部依赖(文件系统、网络、iCloud)抽象到小型、聚焦的协议背后,使 Swift 代码可测试的模式。实现无需 I/O 的确定性测试。
通过将外部依赖(文件系统、网络、iCloud)抽象到小型、聚焦的协议背后,使 Swift 代码可测试的模式。实现无需 I/O 的确定性测试。
每个协议只处理一个外部关注点。
// 文件系统访问
public protocol FileSystemProviding: Sendable {
func containerURL(for purpose: Purpose) -> URL?
}
// 文件读写操作
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
}
// 书签存储(例如用于沙盒应用)
public protocol BookmarkStorageProviding: Sendable {
func saveBookmark(_ data: Data, for key: String) throws
func loadBookmark(for key: String) throws -> Data?
}
public struct DefaultFileSystemProvider: FileSystemProviding {
public init() {}
public func containerURL(for purpose: Purpose) -> URL? {
FileManager.default.url(forUbiquityContainerIdentifier: nil)
}
}
public struct DefaultFileAccessor: FileAccessorProviding {
public init() {}
public func read(from url: URL) throws -> Data {
try Data(contentsOf: url)
}
public func write(_ data: Data, to url: URL) throws {
try data.write(to: url, options: .atomic)
}
public func fileExists(at url: URL) -> Bool {
FileManager.default.fileExists(atPath: url.path)
}
}
public final class MockFileAccessor: FileAccessorProviding, @unchecked Sendable {
public var files: [URL: Data] = [:]
public var readError: Error?
public var writeError: Error?
public init() {}
public func read(from url: URL) throws -> Data {
if let error = readError { throw error }
guard let data = files[url] else {
throw CocoaError(.fileReadNoSuchFile)
}
return data
}
public func write(_ data: Data, to url: URL) throws {
if let error = writeError { throw error }
files[url] = data
}
public func fileExists(at url: URL) -> Bool {
files[url] != nil
}
}
生产代码使用默认值;测试注入模拟。
public actor SyncManager {
private let fileSystem: FileSystemProviding
private let fileAccessor: FileAccessorProviding
public init(
fileSystem: FileSystemProviding = DefaultFileSystemProvider(),
fileAccessor: FileAccessorProviding = DefaultFileAccessor()
) {
self.fileSystem = fileSystem
self.fileAccessor = fileAccessor
}
public func sync() async throws {
guard let containerURL = fileSystem.containerURL(for: .sync) else {
throw SyncError.containerNotAvailable
}
let data = try fileAccessor.read(
from: containerURL.appendingPathComponent("data.json")
)
// 处理数据...
}
}
import Testing
@Test("Sync manager 处理缺失的容器")
func testMissingContainer() async {
let mockFileSystem = MockFileSystemProvider(containerURL: nil)
let manager = SyncManager(fileSystem: mockFileSystem)
await #expect(throws: SyncError.containerNotAvailable) {
try await manager.sync()
}
}
@Test("Sync manager 正确读取数据")
func testReadData() async throws {
let mockFileAccessor = MockFileAccessor()
mockFileAccessor.files[testURL] = testData
let manager = SyncManager(fileAccessor: mockFileAccessor)
let result = try await manager.loadData()
#expect(result == expectedData)
}
@Test("Sync manager 优雅处理读取错误")
func testReadError() async {
let mockFileAccessor = MockFileAccessor()
mockFileAccessor.readError = CocoaError(.fileReadCorruptFile)
let manager = SyncManager(fileAccessor: mockFileAccessor)
await #expect(throws: SyncError.self) {
try await manager.sync()
}
}
#if DEBUG 条件编译而非适当的依赖注入Sendable 一致性npx claudepluginhub aaione/everything-claude-code-zhImplements protocol-based dependency injection in Swift to mock file system, network, and external APIs for deterministic testing with Swift Testing.
Provides protocol-based dependency injection patterns for testable Swift code, with mock implementations for file system, network, and external APIs using Swift Testing.
Provides guidelines, templates, and examples for writing XCTest unit tests in Swift, covering TDD practices, mocking techniques, and best practices.