@Test marks any function as a test — no XCTestCase subclass, no required test prefix on the function name — and #expect(condition) validates a boolean expression, capturing the actual evaluated values automatically for a readable failure message, without needing XCTest's 40-plus specialized assertion functions (XCTAssertEqual, XCTAssertTrue, and the rest). #require works like #expect but exits the test immediately on failure, similar to guard. @Suite groups related tests together. Swift Testing genuinely cannot do UI automation (XCUIApplication) or performance testing (measure{}) — both remain XCTest-only — so real projects run both frameworks side by side in the same test target rather than migrating everything at once.
A basic test with Swift Testing
No class, no inheritance, no "test" prefix required on the function name — @Test alone is what makes this a real, runnable test.
import Testing
@Test func additionWorks() {
let result = Calculator().add(2, 3)
#expect(result == 5)
}
@Test func divisionByZeroThrows() {
#expect(throws: ArithmeticError.self) {
try Calculator().divide(1, by: 0)
}
}The old way: XCTest, still fully supported
The same test in XCTest requires class inheritance and the "test" prefix on the method name — genuinely more ceremony than the Swift Testing equivalent above, though XCTest itself remains fully supported, not deprecated.
import XCTest
class CalculatorTests: XCTestCase {
func testAdditionWorks() {
let result = Calculator().add(2, 3)
XCTAssertEqual(result, 5)
}
}What still requires XCTest
Swift Testing genuinely has no equivalent for either of these yet — UI automation and performance measurement remain XCTest-only, which is why both frameworks coexist in the same test target rather than one fully replacing the other.
// UI testing — Swift Testing has no equivalent
func testLoginFlow() {
let app = XCUIApplication()
app.launch()
app.buttons["Login"].tap()
}
// Performance testing — Swift Testing has no equivalent
func testPerformance() {
measure {
performExpensiveCalculation()
}
}