/swift-testing
Use when writing tests with Swift Testing (@Test, #expect, #require), migrating from XCTest, implementing async tests, or parameterizing tests.
$ npx -y skills add johnrogers/claude-swift-engineering --skill swift-testing --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/swift-testing
Context preview
The summary Claude sees to decide when to auto-load this skill.
Use when writing tests with Swift Testing (@Test, #expect, #require), migrating from XCTest, implementing async tests, or parameterizing tests.
SKILL.md
swift-testing.SKILL.mdname: swift-testing
description: Use when writing tests with Swift Testing (@Test, #expect, #require), migrating from XCTest, implementing async tests, or parameterizing tests.
Swift Testing Framework
Modern testing with Swift Testing framework. No XCTest.
Overview
Swift Testing replaces XCTest with a modern macro-based approach that's more concise, has better async support, and runs tests in parallel by default. The core principle: if you learned XCTest, unlearn it—Swift Testing works differently.
References
- [Apple Documentation](https://developer.apple.com/documentation/testing)
- [Migration Guide](https://steipete.me/posts/2025/migrating-700-tests-to-swift-testing)
Core Concepts
Assertions
| Macro | Use Case | |-------|----------| | `#expect(expression)` | Soft check — continues on failure. Use for most assertions. | | `#require(expression)` | Hard check — stops test on failure. Use for preconditions only. |
Optional Unwrapping
let user = try #require(await fetchUser(id: "123"))
#expect(user.id == "123")
Test Structure
import Testing
@testable import YourModule
@Suite
struct FeatureTests {
let sut: FeatureType
init() throws {
sut = FeatureType()
}
@Test("Description of behavior")
func testBehavior() {
#expect(sut.someProperty == expected)
}
}Assertion Conversions
| XCTest | Swift Testing | |--------|---------------| | `XCTAssert(expr)` | `#expect(expr)` | | `XCTAssertEqual(a, b)` | `#expect(a == b)` | | `XCTAssertNil(a)` | `#expect(a == nil)` | | `XCTAssertNotNil(a)` | `#expect(a != nil)` | | `try XCTUnwrap(a)` | `try #require(a)` | | `XCTAssertThrowsError` | `#expect(throws: ErrorType.self) { }` | | `XCTAssertNoThrow` | `#expect(throws: Never.self) { }` |
Error Testing
#expect(throws: (any Error).self) { try riskyOperation() }
#expect(throws: NetworkError.self) { try fetch() }
#expect(throws: NetworkError.timeout) { try fetch() }
#expect(throws: Never.self) { try safeOperation() }Parameterized Tests
@Test("Validates inputs", arguments: zip(
["a", "b", "c"],
[1, 2, 3]
))
func testInputs(input: String, expected: Int) {
#expect(process(input) == expected)
}**Warning:** Multiple collections WITHOUT zip creates Cartesian product.
Async Testing
@Test func testAsync() async throws {
let result = try await fetchData()
#expect(!result.isEmpty)
}Confirmations
@Test func testCallback() async {
await confirmation("callback received") { confirm in
let sut = SomeType { confirm() }
sut.triggerCallback()
}
}Tags
extension Tag {
@Tag static var fast: Self
@Tag static var networking: Self
}
@Test(.tags(.fast, .networking))
func testNetworkCall() { }Common Pitfalls
1. **Overusing `#require`** — Use `#expect` for most checks 2. **Forgetting state isolation** — Each test gets a NEW instance 3. **Accidental Cartesian product** — Always use `zip` for paired inputs 4. **Not using `.serialized`** — Apply for thread-unsafe legacy tests
Common Mistakes
1. **Overusing `#require`** — `#require` is for preconditions only. Using it for normal assertions means the test stops at first failure instead of reporting all failures. Use `#expect` for assertions, `#require` only when subsequent assertions depend on the value.
2. **Cartesian product bugs** — `@Test(arguments: [a, b], [c, d])` creates 4 combinations, not 2. Always use `zip` to pair arguments correctly: `arguments: zip([a, b], [c, d])`.
3. **Forgetting state isolation** — Swift Testing creates a new test instance per test method. BUT shared state between tests (static variables, singletons) still leak. Use dependency injection or clean up singletons between tests.
4. **Parallel test conflicts** — Swift Testing runs tests in parallel by default. Tests touching shared files, databases, or singletons will interfere. Use `.serialized` or isolation strategies.
5. **Not using `async` naturally** — Wrapping async operations in `Task { }` defeats the purpose. Use `async/await` directly in test function signature: `@Test func testAsync() async throws { }`.
6. **Confirmation misuse** — `confirmation` is for verifying callbacks were called. Using it for assertions is wrong. Use `#expect` for assertions, `confirmation` for callback counts.
Read more
name: swift-testing description: Use when writing tests with Swift Testing (@Test, #expect, #require), migrating from XCTest, implementing async tests, or parameterizing tests.
Swift Testing Framework
Modern testing with Swift Testing framework. No XCTest.
Overview
Swift Testing replaces XCTest with a modern macro-based approach that's more concise, has better async support, and runs tests in parallel by default. The core principle: if you learned XCTest, unlearn it—Swift Testing works differently.
References
- [Apple Documentation](https://developer.apple.com/documentation/testing)
- [Migration Guide](https://steipete.me/posts/2025/migrating-700-tests-to-swift-testing)
Core Concepts
Assertions
| Macro | Use Case | |-------|----------| | `#expect(expression)` | Soft check — continues on failure. Use for most assertions. | | `#require(expression)` | Hard check — stops test on failure. Use for preconditions only. |
Optional Unwrapping
let user = try #require(await fetchUser(id: "123")) #expect(user.id == "123")
Test Structure
import Testing
@testable import YourModule
@Suite
struct FeatureTests {
let sut: FeatureType
init() throws {
sut = FeatureType()
}
@Test("Description of behavior")
func testBehavior() {
#expect(sut.someProperty == expected)
}
}Assertion Conversions
| XCTest | Swift Testing | |--------|---------------| | `XCTAssert(expr)` | `#expect(expr)` | | `XCTAssertEqual(a, b)` | `#expect(a == b)` | | `XCTAssertNil(a)` | `#expect(a == nil)` | | `XCTAssertNotNil(a)` | `#expect(a != nil)` | | `try XCTUnwrap(a)` | `try #require(a)` | | `XCTAssertThrowsError` | `#expect(throws: ErrorType.self) { }` | | `XCTAssertNoThrow` | `#expect(throws: Never.self) { }` |
Error Testing
#expect(throws: (any Error).self) { try riskyOperation() }
#expect(throws: NetworkError.self) { try fetch() }
#expect(throws: NetworkError.timeout) { try fetch() }
#expect(throws: Never.self) { try safeOperation() }Parameterized Tests
@Test("Validates inputs", arguments: zip(
["a", "b", "c"],
[1, 2, 3]
))
func testInputs(input: String, expected: Int) {
#expect(process(input) == expected)
}**Warning:** Multiple collections WITHOUT zip creates Cartesian product.
Async Testing
@Test func testAsync() async throws {
let result = try await fetchData()
#expect(!result.isEmpty)
}Confirmations
@Test func testCallback() async {
await confirmation("callback received") { confirm in
let sut = SomeType { confirm() }
sut.triggerCallback()
}
}Tags
extension Tag {
@Tag static var fast: Self
@Tag static var networking: Self
}
@Test(.tags(.fast, .networking))
func testNetworkCall() { }Common Pitfalls
1. **Overusing `#require`** — Use `#expect` for most checks 2. **Forgetting state isolation** — Each test gets a NEW instance 3. **Accidental Cartesian product** — Always use `zip` for paired inputs 4. **Not using `.serialized`** — Apply for thread-unsafe legacy tests
Common Mistakes
1. **Overusing `#require`** — `#require` is for preconditions only. Using it for normal assertions means the test stops at first failure instead of reporting all failures. Use `#expect` for assertions, `#require` only when subsequent assertions depend on the value.
2. **Cartesian product bugs** — `@Test(arguments: [a, b], [c, d])` creates 4 combinations, not 2. Always use `zip` to pair arguments correctly: `arguments: zip([a, b], [c, d])`.
3. **Forgetting state isolation** — Swift Testing creates a new test instance per test method. BUT shared state between tests (static variables, singletons) still leak. Use dependency injection or clean up singletons between tests.
4. **Parallel test conflicts** — Swift Testing runs tests in parallel by default. Tests touching shared files, databases, or singletons will interfere. Use `.serialized` or isolation strategies.
5. **Not using `async` naturally** — Wrapping async operations in `Task { }` defeats the purpose. Use `async/await` directly in test function signature: `@Test func testAsync() async throws { }`.
6. **Confirmation misuse** — `confirmation` is for verifying callbacks were called. Using it for assertions is wrong. Use `#expect` for assertions, `confirmation` for callback counts.
Claude Code plugin marketplace for modern Swift/SwiftUI development A specialized AI toolkit for building professional iOS/macOS features with modern Swift 6.2, TCA (The Composable Architecture), and SwiftUI.
Other skills on claude-swift-engineering.
- /composable-architecture
Use when building features with TCA (The Composable Architecture), structuring reducers, managing state, handling effects, navigation, or testing TCA features. Covers @Reducer, Store, Effect, TestStore, reducer composition, and TCA patterns.
Open skill - /foundation-models
Use when implementing on-device AI with Apple's Foundation Models framework (iOS 26+), building summarization/extraction/classification features, or using @Generable for type-safe structured output.
Open skill - /generating-swift-package-docs
Use when encountering unfamiliar import statements, exploring dependency APIs, or when user asks "what's import X" or "what does X do". Generates on-demand API documentation for Swift package dependencies.
Open skill - /grdb
Use when writing raw SQL with GRDB, complex joins across 4+ tables, window functions, ValueObservation for reactive queries, or dropping down from SQLiteData for performance. Direct SQLite access for iOS/macOS with type-safe queries and migrations.
Open skill - /haptics
Use when adding haptic feedback for user confirmations (button presses, toggles, purchases), error notifications, or custom tactile patterns (Core Haptics). Covers UIFeedbackGenerator and CHHapticEngine patterns.
Open skill - /ios-26-platform
Use when implementing iOS 26 features (Liquid Glass, new SwiftUI APIs, WebView, Chart3D), deploying iOS 26+ apps, or supporting backward compatibility with iOS 17/18.
Open skill

