{
    "name": "swift-tdd",
    "version": "1.0.0",
    "description": "Internal skill invoked by /programming chain. Use when implementing any feature or bugfix in Swift, before writing implementation code. Use when writing Swift tests with @Test,",
    "system_prompt": "name swift-tdd user-invocable false description Internal skill invoked by /programming chain. Use when implementing any feature or bugfix in Swift, before writing implementation code. Use when writing Swift tests with @Test, Test-Driven Development TDD in Swift: identify test cases via boundary value analysis, then red-green-refactor through them. Heavy reference material is indexed in the programming-skill-references collection in statement-mcp. When to Use Implementing any feature or bugfix in a Swift project Writing new tests (use Swift Testing, not XCTest) Identifying what to test / edge cases / coverage gaps Testing async/await, actors, @MainActor code Dependency injection for testability Snapshot or XCUITest for UI features When NOT to Use Performance benchmarks (use XCTest measure {} ) Objective-C test code (use XCTest) Source code review or debugging Phase 1: Boundary Value Analysis Run BEFORE writing tests. Produces a prioritized test case list for TDD's RED phase. BVA Algorithm Step 1: Enumerate Inputs Everything the function reads: explicit parameters, self properties, closure captures, globals, environment, external data. Do not skip implicit inputs. Step 2: Classify Input Types Numeric, String, Collection, Nullable, Boolean, Enum/Union, Date/Time, Float, Composite. Each type class has specific boundary values — see boundary-catalog in programming-skill-references collection. Step 3: Scan for Decision Points Every code construct that partitions input space: comparisons, switch/match, loop conditions, guard clauses, try/catch, type narrowing, null checks, .count comparisons, ternaries. Step 4: Extract Boundary Values For each decision point, select three test points: on-boundary, off-below, off-above. See references/boundary-catalog.md for the operator table and increment rules. Step 5: Handle Compound Conditions AND ( A && B ): Use MC/DC — N+1 tests where each condition independently flips the outcome. OR ( A || B ): Same MC/DC approach. Nested/complex : Decompose into decision table. Step 6: Derived and State-Dependent Boundaries Derived: if (a + b > limit) → boundary is a + b = limit , test at limit±1 State-dependent: identify distinct states, test each state × boundary combination Step 7: Produce Test Case List Order by priority: degenerate/empty → minimal valid → nominal → upper boundaries → invalid → type-specific edges → compound interactions → state × boundary. Output format per case: N. test_name: description Input: { param1: value, param2: value } Expected: outcome Boundary: which boundary this tests Phase 2: TDD Cycle (Swift) RED: Write the Failing Test import Testing @Suite ( \"Cart\" ) struct CartTests { let sut: Cart init () { sut = Cart (catalog: MockCatalog ()) } @Test ( \"Rejects negative quantity\" ) func rejectNegativeQuantity () throws { #expect(throws: CartError .invalidQuantity) { try sut.add(item: .widget, quantity: - 1 ) } } } Rules: @Test with display name. One behavior per test. #expect for soft assertions, #require for preconditions. Struct suite with init() . Inject dependencies via initializer. Verify RED swift test --filter \"CartTests/rejectNegativeQuantity\" # SPM xcodebuild test -scheme MyApp -destination 'platform=macOS' \\ -only-testing 'MyAppTests/CartTests/rejectNegativeQuantity' # Xcode Confirm: test fails (not errors), failure matches expected behavior, fails because feature is missing. GREEN: Minimal Implementation Simplest code that makes the test pass. Don't add features or refactor. Verify GREEN swift test # SPM: all tests xcodebuild test -scheme MyApp ... # Xcode: all tests All tests pass, no warnings. REFACTOR After green only. Remove duplication, improve names. Keep all tests green. Don't add behavior. Repeat Next failing test from the BVA list. Testing Async, Actors, @MainActor @Test func fetchUser () async throws { let user = try await api.fetchUser(id: \"123\" ) #expect(user.name == \"Alex\" ) } @Test func counterIncrements () async { let counter = Counter () // actor await counter.increment() #expect( await counter.value == 1 ) } @Test @MainActor func viewModelLoads () async { let vm = ViewModel () await vm.loadData() #expect(vm.title == \"Loaded\" ) } Mock objects in concurrent tests must be Sendable — use actor mocks. Swift Testing runs tests in parallel by default. Use .serialized only when tests share external state that cannot be isolated. Dependency Injection Swift has no runtime mock generation. Every seam must be explicit. Protocol-based (primary): define protocol, implement live + mock versions, inject via init. Closure injection (lighter): var fetchUser: (String) async throws -> User = LiveAPI().fetchUser Default parameter : init(api: APIClient = LiveAPIClient()) Test data factories: extension User { static func fixture(name: String = \"Test\") -> User { ... } } XCTest Migration XCTest Swift Testing XCTAssertEqual(a, b) #expect(a == b) XCTAssertNil(x) #expect(x == nil) try XCTUnwrap(x) try #require(x) setUpWithError() init() throws XCTestExpectation await confirmation(...) func testFoo() @Test func foo() XCTSkip .disabled(\"reason\") Both frameworks coexist. Do not subclass XCTestCase for Swift Testing tests. Swift TDD: What's Different Value types reduce mocking : pure functions on structs need no mocks Type system replaces tests : don't test what the compiler enforces (type mismatch, exhaustive switch, non-optional, Sendable) Parallel by default : fix shared state, don't reach for .serialized No runtime mocking : every dep needs protocol/closure seam. Code-gen tools (Mockolo, Sourcery) generate mocks at build time Layered Testing All units must be tested, and all runtime paths tested from unit outward. N layers between unit and user behavior = N layers of tests. Layer Proves Test type 1 Evaluator produces correct output Unit test 2 Model delivers result to display state Integration test 3 View receives and renders Snapshot/UI test Rules: passing unit test proves the unit works, NOT the feature. Each layer tests real composition (not mocks of the layer below). No untested layer boundaries. UI Feature TDD (Outside-In Double Loop) Outer acceptance test (snapshot/XCUITest) stays red while inner unit tests drive implementation. Write outer test (RED) — snapshot or XCUITest for completed feature Identify components (VM properties, model methods, view elements) Inner loop: unit test → implement → refactor for each VM behavior Implement view last (GREEN outer) Testing pyramid : ~70% unit / ~20% snapshot / ~10% XCUITest Question Test Type Logic with no UI dependency? Unit View renders correct elements? Snapshot Dark mode / large text correct? Snapshot Multi-screen flow works end-to-end? XCUITest System permissions/alerts work? XCUITest Snapshot Testing import Testing import SnapshotTesting @Test func lightAndDark () { let view = ItemListView (viewModel: . init (items: Item .samples)) assertSnapshot(of: view, as: .image(layout: .device(config: .iPhone13))) assertSnapshot(of: view, as: .image( layout: .device(config: .iPhone13), traits: UITraitCollection (userInterfaceStyle: .dark) ), named: \"dark\" ) } Determinism: pin Xcode + simulator in CI, perceptualPrecision: 0.98 , disable animations, fix locale/timezone. XCUITest Reserve for 5-10 critical journeys. Page Object pattern mandatory. struct LoginScreen { let app: XCUIApplication var emailField: XCUIElement { app.textFields[ \"emailField\" ] } var loginButton: XCUIElement { app.buttons[ \"loginButton\" ] } @discardableResult func login ( email : String , password : String ) -> HomeScreen { emailField.tap(); emailField.typeText(email) loginButton.tap() return HomeScreen (app: app) } } Rules: .accessibilityIdentifier() for element identification. waitForExistence(timeout:) for waits — never sleep() . Each test resets state via launch arguments. Common Mistakes Mistake Fix Using XCTest for new unit tests Swift Testing ( @Test , #expect ) Missing await on actor assertions #expect(await counter.value == 1) Non-Sendable mock in concurrent tests Actor mock or @unchecked Sendable with lock Tests depend on execution order Make independent, or .serialized #expect where #require needed Preconditions need #require Modifying test to match buggy output Fix the implementation, not the test 2-3 test cases for function with branches Run BVA algorithm — almost certainly incomplete Only testing explicit parameters Check implicit state, closures, globals Skipping derived boundaries a + b > limit has boundary even if no single param does Red Flags Writing import XCTest for a new unit test Test passes immediately (testing existing behavior) Mock type isn't Sendable but tests run in parallel \"This function is too simple to analyze\" — it has boundaries \"I'll just test happy path and one error\" — that's not BVA Using accessibilityIdentifier without verifying it exists in view source",
    "model_config": {
        "provider": "deepseek",
        "model": "deepseek-chat",
        "temperature": 0.7,
        "max_tokens": 4096,
        "top_p": 0.9
    },
    "trigger_words": [],
    "source": "DeepseekModel",
    "source_url": "https://deepseekmodel.com/skill?id=strongai-claude-skills-programming-swift-tdd-skill-md"
}