Skip to main content

test-contract

Generate protocol/interface test suites that any implementation must pass. Define the contract once, test every implementation. Use when designing protocols or swapping implementations.

Quellinformationen

Repository
rshankras/claude-code-apple-skills
Letzte Quellaktivität
16. Juli 2026 um 14:28
Erkannte Sprache von SKILL.md
Englisch
Sterne
770
Forks
74

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
test-contract
description
Generate protocol/interface test suites that any implementation must pass. Define the contract once, test every implementation. Use when designing protocols or swapping implementations.
allowed-tools
["Read","Write","Edit","Glob","Grep","Bash","AskUserQuestion"]
last_verified
2026-07-16T00:00:00.000Z
review_by
2027-06-22T00:00:00.000Z
# Test Contract Define behavioral contracts as test suites. Any class conforming to a protocol must pass the contract tests. Ensures consistent behavior across implementations — human-written, AI-generated, or mock. ## When This Skill Activates Use this skill when the user: - Designs a protocol and wants to ensure conformance quality - Has multiple implementations of the same interface (e.g., real + mock + in-memory) - Says "test the protocol" or "contract test" - Wants to swap implementations safely (e.g., CoreData → SwiftData) - Wants to ensure AI-generated implementations meet the spec ## Why Contract Tests ``` Protocol: DataStore ├── SQLiteDataStore → must pass contract tests ├── InMemoryDataStore → must pass contract tests ├── MockDataStore → must pass contract tests └── CloudDataStore → must pass contract tests ``` Write the contract once. Every implementation proves it works by passing the same tests. ## Process ### Phase 1: Identify the Protocol ``` Grep: "protocol.*\\{" to find protocols Read: protocol definition ``` Understand: - [ ] All required methods and properties - [ ] Expected behavior for each method - [ ] Error conditions and edge cases - [ ] Thread safety requirements - [ ] State invariants (e.g., count matches items.count) ### Phase 2: Define Contract Behaviors For each protocol method, define required behaviors: ```markdown ## DataStore Contract ### save(_ item:) - Saving a new item increases count by 1 - Saved item is retrievable by ID ### fetch(id:) - Returns item when it exists - Returns nil when item doesn't exist - Returns most recently saved version ### delete(id:) - Deleting existing item decreases count by 1 - Deleted item is no longer fetchable ### fetchAll() - Returns all saved items - Returns empty array when store is empty - Items are in consistent order (insertion or specified) ### Invariants - count == fetchAll().count (always) - save then fetch returns same item - delete then fetch returns nil ``` ### Phase 3: Generate Contract Test Suite #### Pattern: Generic Test Suite ```swift import Testing /// Contract tests for any DataStore implementation. /// Subclass or call with your concrete implementation. struct DataStoreContractTests<Store: DataStore> { let makeStore: () -> Store init(makeStore: @escaping () -> Store) { self.makeStore = makeStore } // MARK: - save(_ item:) @Test("save increases count") func saveIncreasesCount() async throws { let store = makeStore() let item = Item(id: "1", title: "Test") try await store.save(item) #expect(store.count == 1) } @Test("save then fetch returns same item") func saveAndFetch() async throws { let store = makeStore() let item = Item(id: "1", title: "Test") try await store.save(item) let fetched = try await store.fetch(id: "1") #expect(fetched?.title == "Test") } @Test("save existing item updates it") func saveUpdates() async throws { let store = makeStore() try await store.save(Item(id: "1", title: "Original")) try await store.save(Item(id: "1", title: "Updated")) let fetched = try await store.fetch(id: "1") #expect(fetched?.title == "Updated") #expect(store.count == 1) } @Test("save throws on invalid item") func saveInvalidThrows() async { let store = makeStore() let invalid = Item(id: "1", title: "") await #expect(throws: DataStoreError.invalidItem) { try await store.save(invalid) } } // MARK: - fetch(id:) @Test("fetch returns nil for non-existent ID") func fetchNonExistent() async throws { let store = makeStore() let result = try await store.fetch(id: "nonexistent") #expect(result == nil) } // MARK: - delete(id:) @Test("delete removes item") func deleteRemoves() async throws { let store = makeStore() try await store.save(Item(id: "1", title: "Test")) try await store.delete(id: "1") #expect(store.count == 0) let fetched = try await store.fetch(id: "1") #expect(fetched == nil) } @Test("delete non-existent does nothing") func deleteNonExistent() async throws { let store = makeStore() try await store.delete(id: "nonexistent") #expect(store.count == 0) } // MARK: - fetchAll() @Test("fetchAll returns all items") func fetchAll() async throws { let store = makeStore() try await store.save(Item(id: "1", title: "A")) try await store.save(Item(id: "2", title: "B")) let all = try await store.fetchAll() #expect(all.count == 2) } @Test("fetchAll returns empty when store is empty") func fetchAllEmpty() async throws { let store = makeStore() let all = try await store.fetchAll() #expect(all.isEmpty) } // MARK: - Invariants @Test("count matches fetchAll count") func countInvariant() async throws { let store = makeStore() try await store.save(Item(id: "1", title: "A")) try await store.save(Item(id: "2", title: "B")) try await store.delete(id: "1") let all = try await store.fetchAll() #expect(store.count == all.count) } } ``` #### Running Contract Tests Per Implementation ```swift @Suite("InMemoryDataStore Contract") struct InMemoryDataStoreContractTests { let contract = DataStoreContractTests { InMemoryDataStore() } @Test("save increases count") func saveIncreasesCount() async throws { try await contract.saveIncreasesCount() } @Test("save then fetch returns same item") func saveAndFetch() async throws { try await contract.saveAndFetch() } // ... all contract tests } @Suite("SQLiteDataStore Contract") struct SQLiteDataStoreContractTests { let contract = DataStoreContractTests { SQLiteDataStore(path: ":memory:") } @Test("save increases count") func saveIncreasesCount() async throws { try await contract.saveIncreasesCount() } // ... all contract tests } ``` ## Common Contract Categories ### Repository / Data Store - CRUD operations (create, read, update, delete) - Query/filter behavior - Ordering guarantees - Uniqueness constraints - Empty state handling ### Network Client - Successful response parsing - Error response handling (4xx, 5xx) - Timeout behavior - Retry logic - Request construction (headers, body) ### Cache - Store and retrieve - Expiration/TTL - Thread safety - Persistence across init ### Authentication - Login with valid credentials - Reject invalid credentials - Token refresh - Session expiration - Logout clears state ## Output Format ```markdown ## Contract Tests: [Protocol Name] ### Protocol ```swift protocol DataStore { ... } ``` ### Behaviors Tested | Behavior | Tests | Edge Cases | |----------|-------|------------| | save | 3 | empty title, duplicate ID | | fetch | 2 | non-existent ID | | delete | 2 | non-existent ID | | fetchAll | 2 | empty store | | invariants | 1 | count consistency | ### Implementations Tested - [x] InMemoryDataStore — all passing - [x] SQLiteDataStore — all passing - [ ] CloudDataStore — pending implementation ### Files Created - `Tests/Contracts/DataStoreContractTests.swift` - `Tests/Contracts/InMemoryDataStoreContractTests.swift` ``` ## References - `testing/tdd-feature/` — for TDD workflow using contract tests - `generators/test-generator/` — for standard test generation - Design by Contract (Bertrand Meyer) — theoretical foundation
Auf GitHub ansehen