swift-testing

Swift Testing Framework

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "swift-testing" with this command: npx skills add johnrogers/claude-swift-engineering/johnrogers-claude-swift-engineering-swift-testing

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

  • Migration Guide

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

  • Overusing #require — Use #expect for most checks

  • Forgetting state isolation — Each test gets a NEW instance

  • Accidental Cartesian product — Always use zip for paired inputs

  • Not using .serialized — Apply for thread-unsafe legacy tests

Common Mistakes

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.

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]) .

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.

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.

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 { } .

Confirmation misuse — confirmation is for verifying callbacks were called. Using it for assertions is wrong. Use #expect for assertions, confirmation for callback counts.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

swift-style

No summary provided by upstream source.

Repository SourceNeeds Review
General

ios-hig

No summary provided by upstream source.

Repository SourceNeeds Review
General

swiftui-patterns

No summary provided by upstream source.

Repository SourceNeeds Review