Summary
Swift Testing simplifies migration from XCTest with interoperability.
Parameterized tests and exit tests supercharge testing in Swift.
Xcode 27 defaults to interoperability, easing transition to Swift Testing.
Contribute to Swift Testing. It’s open source and community-driven.

Presenters
Jerry Chen, Developer Tools
Swift Testing Overview
Introduction: Swift Testing introduced in Xcode 16 as a modern library for writing tests, with an expressive interface, and built for Swift concurrency.
Core Macros:
@Testfor declaring tests.#expectfor creating expectations.Issue.recordreplacesXCTFailfor unconditional failures.
import Testing
@testable import DemoApp
@Test func `Default climate: tropical`() async throws {
let fruit = Fruit(name: "Coconut")
#expect(fruit.climate == .tropical)
}Migration Strategy
Keep Existing Tests: Leave most XCTests in place; modify a few at a time.
Interoperability:
Supports calling APIs across XCTest and Swift Testing.
Modes:
Limited: Cross-framework issues as warnings.
Complete: Issues as errors. Recommended.
Strict: Fatal errors from XCTest issues.
None: Opt-out, but not recommended.
func testUniqueFruitNames() async throws {
assertUnique(Market.fruits + [Fruit.lychee])
}
// TestHelpers.swift
func assertUnique(_ fruits: [Fruit], file: StaticString = #filePath, line: UInt = #line) {
var uniqueNames = Set<String>()
for name in fruits.map(\.name) {
if !uniqueNames.insert(name).inserted {
XCTFail("Duplicate name: \(name)", file: file, line: line)
}
}
}import Testing
func assertUnique(_ fruits: [Fruit], sourceLocation: SourceLocation = ...) {
var uniqueNames = Set<String>()
for name in fruits.map(\.name) {
if !uniqueNames.insert(name).inserted {
Issue.record("Duplicate name: \(name)", sourceLocation: sourceLocation)
}
}
}Test Framework Interoperability
Usage: Allows seamless use of helper functions across testing frameworks.
Modes:
Change modes with Test Plan Settings.
Use environment variable for Swift Package projects.
SWIFT_TESTING_XCTEST_INTEROP_MODE=strict swift test

| XCTest | Swift Testing |
|---|---|
XCTFail | Issue.record(...) |
XCTAssert, XCTAssertTrue, XCTAssertFalse | #expect(...) try#require(...) |
XCTAssertNil, XCTAssertNotNil | |
XCTAssertEqual, XCTAssertNotEqual | |
XCTAssertIdentical, XCTAssertNotIdentical | |
XCTAssertGreaterThan, XCTAssertLessThanOrEqual | |
XCTAssertGreaterThanOrEqual,XCTAssertLessThan | |
| - | withKnownIssue { ... } |
| - | try Test.cancel() |
Advanced Testing Features
Parameterized Tests: Run tests with different arguments in parallel for efficiency.
struct BirdTests { @Test func `Birds flap wings successfully`() async throws { for bird in Aviary.birds { for count in (40...100) { try await bird.flapWings(count: count) } } } }struct BirdTests { @Test(arguments: Aviary.birds, 40...100) func `Birds flap wings successfully`(bird: Bird, count: Int) async throws { try await bird.flapWings(count: count) } }Exit Tests: Test code that might crash, running in isolated processes to ensure stability.
// In `Bird.init(...)` if name.isEmpty { preconditionFailure("Bird name cannot be empty") } extension BirdTests { @Test func `Bird with empty name crashes`() async throws { await #expect(processExitsWith: .failure) { _ = Bird(name: "") } } }

Tips for Migrating
Skip Tests: Use
Test.cancelin Swift Testing.let isFall = false // XCTest func testSwallowFallMigration() async throws { try XCTSkipIf(!isFall, "Wrong season for migration") // ... } // Test.cancel interoperability from Swift Testing func testSwallowFallMigration() async throws { if !isFall { try Test.cancel("Wrong season for migration") } // ... } // ✅ Prefer test trait in Swift Testing @Test(.enabled(if: isFall, "Wrong season for migration")) func `Swallow fall migration`() async throws { // ... }Halt on Failure: Use
#requireto stop tests on first failed assertion.func testExample() async throws { #expect(Fruit.banana.climate == .temperate) try #require(Fruit.banana == Fruit.plantain) XCTFail("This is never reached") }
Contribution and Community
Open Source: Part of SwiftLang on GitHub; contributions are welcome.
Governance: Managed by the Testing Workgroup and guided by Swift Evolution.
Community Engagement: Join discussions on Swift Forums.
Recommendations
Focus on New Tests: Use Swift Testing for new tests while maintaining existing XCTests.
Leverage Interoperability: Replace XCTest API gradually with Swift Testing API.
Explore New Tools: Utilize parameterized and exit tests to enhance testing capabilities.
