Install
Terminal · npx$
npx skills add https://github.com/affaan-m/everything-claude-code --skill swift-protocol-di-testingWorks with Paperclip
How Swift Protocol Di Testing fits into a Paperclip company.
Swift Protocol Di Testing drops into any Paperclip agent that handles this kind of work. Assign it to a specialist inside a pre-configured PaperclipOrg company and the skill becomes available on every heartbeat — no prompt engineering, no tool wiring.
S
SaaS FactoryPaired
Pre-configured AI company — 18 agents, 18 skills, one-time purchase.
$27$59
Explore packSource file
SKILL.md190 linesExpandCollapse
---name: swift-protocol-di-testingdescription: Protocol-based dependency injection for testable Swift code — mock file system, network, and external APIs using focused protocols and Swift Testing.origin: ECC--- # Swift Protocol-Based Dependency Injection for Testing Patterns for making Swift code testable by abstracting external dependencies (file system, network, iCloud) behind small, focused protocols. Enables deterministic tests without I/O. ## When to Activate - Writing Swift code that accesses file system, network, or external APIs- Need to test error handling paths without triggering real failures- Building modules that work across environments (app, test, SwiftUI preview)- Designing testable architecture with Swift concurrency (actors, Sendable) ## Core Pattern ### 1. Define Small, Focused Protocols Each protocol handles exactly one external concern. ```swift// File system accesspublic protocol FileSystemProviding: Sendable { func containerURL(for purpose: Purpose) -> URL?} // File read/write operationspublic 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. Create Default (Production) Implementations ```swiftpublic 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) }}``` ### 3. Create Mock Implementations for Testing ```swiftpublic 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 }}``` ### 4. Inject Dependencies with Default Parameters Production code uses defaults; tests inject mocks. ```swiftpublic 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") ) // Process data... }}``` ### 5. Write Tests with Swift Testing ```swiftimport Testing @Test("Sync manager handles missing container")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 reads data correctly")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 handles read errors gracefully")func testReadError() async { let mockFileAccessor = MockFileAccessor() mockFileAccessor.readError = CocoaError(.fileReadCorruptFile) let manager = SyncManager(fileAccessor: mockFileAccessor) await #expect(throws: SyncError.self) { try await manager.sync() }}``` ## Best Practices - **Single Responsibility**: Each protocol should handle one concern — don't create "god protocols" with many methods- **Sendable conformance**: Required when protocols are used across actor boundaries- **Default parameters**: Let production code use real implementations by default; only tests need to specify mocks- **Error simulation**: Design mocks with configurable error properties for testing failure paths- **Only mock boundaries**: Mock external dependencies (file system, network, APIs), not internal types ## Anti-Patterns to Avoid - Creating a single large protocol that covers all external access- Mocking internal types that have no external dependencies- Using `#if DEBUG` conditionals instead of proper dependency injection- Forgetting `Sendable` conformance when used with actors- Over-engineering: if a type has no external dependencies, it doesn't need a protocol ## When to Use - Any Swift code that touches file system, network, or external APIs- Testing error handling paths that are hard to trigger in real environments- Building modules that need to work in app, test, and SwiftUI preview contexts- Apps using Swift concurrency (actors, structured concurrency) that need testable architectureRelated skills
Agent Eval
Install Agent Eval skill for Claude Code from affaan-m/everything-claude-code.
Agent Harness Construction
Install Agent Harness Construction skill for Claude Code from affaan-m/everything-claude-code.
Agent Payment X402
Install Agent Payment X402 skill for Claude Code from affaan-m/everything-claude-code.