Swift Testing: The Complete Guide from Swift 6.0 to 6.2
Published on Β· Updated Β· 24 min
Swift Testing represents a revolution in the Apple testing ecosystem. Designed natively for Swift, this modern framework progressively replaces XCTest with an expressive syntax, powerful macros, and perfect integration with Swift Concurrency. This comprehensive guide covers everything you need to know, from fundamentals to advanced features in Swift 6.2.
Why Swift Testing?
After more than 10 years of XCTest, Apple has completely rethought the testing approach. Swift Testing is not an evolution of XCTest β it's a complete rewrite, designed for modern Swift.
The main motivations:
Declarative syntax with native Swift macros
First-class support for async/await and Swift Concurrency
Natively integrated parameterized tests
Flexible organization with tags and traits
Rich and contextual error messages
Open source and evolvable via Swift Evolution
The central philosophy: testing should not be a burden. Swift Testing makes writing tests as natural as writing production code.
Swift Testing vs XCTest
Before diving into details, here's a quick comparison of the two approaches:
| Aspect | XCTest | Swift Testing |
|---|---|---|
Syntax | Classes, | Structs, |
Assertions |
|
|
Async |
| Native |
Parameterization | Manual (loops) |
|
Organization | Class inheritance | Tags, traits, suites |
Setup/Teardown |
|
|
Parallelization | Global configuration | Default, isolated |
UI Tests | Yes | No (stays XCTest) |
Performance Tests | Yes | No (stays XCTest) |
Swift Testing and XCTest can coexist in the same project. UI and performance tests remain XCTest-exclusive.
Timeline and evolutions
Swift Testing has evolved rapidly since its introduction:
Swift 5.9 β Experimental introduction
First appearance of the framework in preview, allowing early adopters to test the approach.
Swift 6.0 β September 2024
Official release with Xcode 16. The framework becomes production-ready with:
@Testand@Suitemacros#expect()and#require()assertionsParameterized tests
Basic traits (.enabled, .disabled, .bug, .timeLimit)
Tags for organization
Swift 6.1 β March 2025
Three major proposals integrated:
ST-0005: Ranged confirmations β Verify a callback is called N times
ST-0006: Return errors from expect throws β Retrieve the thrown error
ST-0007: Test Scoping Traits β Before/after code without global state
Swift 6.2 β September 2025
Significant evolutions with Xcode 26:
ST-0008: Exit Tests β Test crashes (precondition, fatalError)
ST-0009: Attachments β Attach files to test results
ST-0010: evaluate() on ConditionTrait
Raw identifier display names with backticks
Future roadmap
In active discussion:
ST-0011: Issue Handling Traits β Modify/filter issues before reporting
Test Issue Warnings β Issues that don't fail the suite
Installation and configuration
Package.swift
For a Swift Package, add the test dependency:
Xcode
In Xcode 16+, Swift Testing is automatically available. Simply create a file in your test target:
System requirements
To develop with Swift Testing:
macOS 14.5+ for Xcode 16
macOS 15+ for Xcode 26 (Swift 6.2)
The tested code can target older iOS/macOS versions
Coexistence with XCTest
You can have XCTest and Swift Testing files in the same target:
Both frameworks run together via swift test or the Xcode Test Navigator.
Fundamental syntax
@Test β Declaring a test
The @Test macro marks a function as a test:
Unlike XCTest, no need to prefix with test. The function name is free.
Display names
Add a readable name for reports:
Raw identifiers (Swift 6.2)
Swift 6.2 allows using backticks for expressive names:
The function name directly becomes the display name, without duplication.
@Suite β Organizing tests
Group related tests in a suite:
Suites can be nested:
Modern assertions
#expect() β Standard verification
#expect() is the main assertion. It accepts any boolean expression:
On failure, Swift Testing displays a rich contextual message showing actual values.
#require() β Mandatory preconditions
#require() stops the test immediately if the condition fails. Useful for preconditions:
#require() can also unwrap optionals:
Testing errors
To verify that a function throws an error:
Retrieving the error (Swift 6.1 β ST-0006)
Swift 6.1 allows retrieving the error for additional assertions:
XCTest β Swift Testing mapping
| XCTest | Swift Testing |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Asynchronous tests
Swift Testing natively supports async/await:
Complete API example
Timeouts
Use the .timeLimit trait to avoid blocking tests:
Parameterized tests
Parameterized tests run the same test with different inputs:
This test runs 5 times, once per argument.
Multiple arguments
Using CaseIterable
For enums, use allCases:
Parameter combinations
Test all combinations of two sets:
Zip for corresponding pairs
To test input/output pairs:
Traits β Test configuration
Traits modify the behavior of a test or suite.
.enabled(if:) and .disabled()
Conditionally enable or disable:
.bug() β Referencing issues
Document associated bugs:
.timeLimit() β Timeout
Set a time limit:
evaluate() for ConditionTrait (Swift 6.2)
Swift 6.2 allows evaluating conditions outside tests:
Tags β Flexible organization
Tags allow categorizing and filtering tests.
Creating tags
Define your tags in an extension:
Applying tags
Command line filtering
Tags view in Xcode
In the Test Navigator (β-6), click the tag icon to see your tests organized by tags rather than by file.
Advanced organization
Fixtures with init/deinit
Use struct initialization for setup:
Each test receives a fresh instance of the suite, thus a clean database.
Accessing the current test
For logging or debugging:
CustomTestStringConvertible
Customize type display in reports:
Confirmations and async expectations
confirmation() β Verifying callbacks
For callback-based APIs:
Ranged confirmations (Swift 6.1 β ST-0005)
Verify a callback is called a precise number of times:
withKnownIssue() β Known bugs
Mark a test as having a known bug without disabling it:
The test runs, the failure is recorded but doesn't fail the suite.
Test Scoping Traits (Swift 6.1 β ST-0007)
Test Scoping Traits allow running before/after code without mutable global state.
Defining a scope trait
Using the scope
Benefits:
No mutable global state
Compatible with parallelization
Reusable across suites
Uses Structured Concurrency
Exit Tests (Swift 6.2 β ST-0008)
Exit Tests allow verifying that code terminates the process (crash, precondition, fatalError).
Why it's revolutionary
Before Swift 6.2, testing a crash was nearly impossible. You had to create a separate CLI and use external tools. Now:
Practical example
How it works
The code in the block runs in a separate process. Swift Testing verifies the process exit code.
Attachments (Swift 6.2 β ST-0009)
Attachments allow attaching files to test results to facilitate diagnosis.
Attaching an image
Attaching JSON
Attaching logs
Attachments appear in Xcode and CI reports, greatly facilitating failure diagnosis.
Migration from XCTest
Progressive strategy
Don't migrate everything at once. Recommended approach:
New tests β Swift Testing
Refactored tests β Swift Testing
Stable tests β Migrate progressively
UI/Performance tests β Stay XCTest
Migration example
Before (XCTest):
After (Swift Testing):
What stays in XCTest
Some features remain XCTest-exclusive:
UI tests with XCUITest
Performance tests with
measure {}Certain CI-specific integrations
XCTActivity for log hierarchy
CI/CD integration
Xcode Cloud
Swift Testing works natively with Xcode Cloud. No special configuration required.
GitHub Actions
Test reports
Swift Testing supports multiple report formats:
Runtime Issue Detection (Xcode 26)
Xcode 26 introduces automatic detection of runtime issues in tests:
Thread Sanitizer violations
Memory leaks
Main thread violations
These issues appear as warnings or errors depending on your configuration.
Best practices
Naming conventions
Use descriptive English names:
One test = one logical assertion
Prefer multiple focused tests to one large test:
Test isolation
Each test must be independent:
Test performance
Parallelize as much as possible (it's the default). For tests that can't be parallelized:
Official resources
Apple documentation
WWDC Sessions
WWDC 2024 β Meet Swift Testing: Complete introduction
WWDC 2024 β Go further with Swift Testing: Advanced features
WWDC 2025 β What's new in Swift Testing: Exit tests, Attachments
GitHub
Swift Evolution Proposals
| Proposal | Title | Version |
|---|---|---|
ST-0005 | Ranged confirmations | Swift 6.1 |
ST-0006 | Return errors from expect throws | Swift 6.1 |
ST-0007 | Test Scoping Traits | Swift 6.1 |
ST-0008 | Exit tests | Swift 6.2 |
ST-0009 | Attachments | Swift 6.2 |
ST-0010 | evaluate() on ConditionTrait | Swift 6.2 |
ST-0011 | Issue Handling Traits | In review |
Community
Hacking with Swift β What's new in Swift Testing
Swift Testing represents the future of testing on Apple platforms. Its progressive adoption, coexistence with XCTest, and rapid evolutions make it an obvious choice for any new Swift project.