Swift Testing
Swift Testing is the open-source test framework bundled with the Swift 6 toolchain and Xcode 16+; it requires no package dependency. New Swift unit tests SHOULD use it. It runs alongside XCTest in the same target, so migration can proceed incrementally.
When to use it
- For new Swift unit tests, you SHOULD author with Swift Testing rather than XCTest.
- You MUST NOT rewrite passing XCTest suites solely to switch frameworks; migrate opportunistically when a test changes.
- XCTest is still required for UI tests (
XCUIApplication) and for XCTest-based performance measurement (measure {}); Swift Testing does not replace these as of Xcode 16. Keep those in XCTest.
Core API
@Testmarks a function as a test. The function MAY be a global function or a method, and MAY beasync,throws, or isolated to a global actor (e.g.@MainActor). A descriptive display name SHOULD be passed:@Test("Parses ISO-8601 dates").#expect(expr)records a failure but continues; use it for ordinary assertions. It captures sub-expression values, so a single#expect(a == b)reports both operands on failure — you SHOULD NOT add a custom message that restates the expression.#require(expr)throws and halts the test when the expectation fails; use it for preconditions whose failure makes the rest of the test meaningless.try #require(optional)unwraps an optional and aborts onnil, replacing force-unwraps.- Use
#expect(throws:)/#require(throws:)to assert error behavior instead ofdo/catch.
Suites and organization
- Group related tests with
@Suiteon a type (often astruct). A type containing@Testmethods is treated as a suite implicitly, but you SHOULD annotate it to set a name or traits. - Per-test state lives in stored properties; fresh suite instances are created per test, so
initis the setup anddeinitis the teardown. You SHOULD prefer this over shared mutable static state to keep tests independent (seeagenticdevelopercookbook://guidelines/implementing/testing/unit-test-patterns).
Parameterized tests
- Pass
arguments:to run one test body over many inputs:@Test(arguments: [1, 2, 3]). Each case is reported and rerun independently. - Use
zip(...)for paired inputs to avoid an unintended Cartesian product across two collections. - You SHOULD prefer parameterization over hand-written loops so each case surfaces as a distinct result.
Traits and tags
- Attach traits for behavior and metadata:
.disabled("reason"),.bug("url"),.timeLimit(.minutes(1)),.enabled(if:), and serialization via.serialized. - Define tags with
@Tagand apply them to filter/organize runs (e.g..tags(.network)). You SHOULD keep a small, shared tag vocabulary rather than ad-hoc per-file tags.
Conventions for this codebase
- Target the latest Swift 6.2.x toolchain and write tests that are clean under strict concurrency; annotate
@MainActoron@Testfunctions that touch main-actor state rather than dispatching manually. - Follow one-entity-per-file: one suite
structper file, with nested helpers in anextension. - Run with
swift test(SwiftPM) or the Xcode test action; both discover Swift Testing and XCTest in the same target.