What each piece does, with Apple's example and the first Swift and Xcode version that has it, as Apple's page for that symbol states.
@Test
Marks a function as a test. It can be a global function or a method; the name does not need a test prefix. Pass a display name as the first argument.
@Test func engineWorks() {
...
}
@Test("Food truck exists") func foodTruckExists() { ... }
Swift 6.0, Xcode 16.0 Apple's page
@Suite
Groups tests in a type. Any type with @Test methods is a suite; @Suite lets you add a display name or traits.
@Suite struct FoodTruckTests {
@Test func engineWorks() { ... }
}
Swift 6.0, Xcode 16.0 Apple's page
#expect
Checks a condition and records a failure with the values it saw. The test keeps running.
#expect(calculator.total(of: [3, 3]) == 7)
// Expectation failed: calculator.total(of: [3, 3]) == 7
Swift 6.0, Xcode 16.0 Apple's page
#require
Like #expect, but throws and stops the test when it fails. With an optional, it unwraps the value or stops the test.
let customer = try #require(Customer(id: 123))
try #require(engine.parts.first != nil)
Swift 6.0, Xcode 16.0 Apple's page
#expect(throws:)
Checks that code throws (or, with Never.self, does not throw). The returned value is the error that was thrown.
#expect(throws: (any Error).self) { try f() }
let error = #expect(throws: (any Error).self) { try f() }
#expect(throws: Never.self) { try f() }
Swift 6.0, Xcode 16.0 Apple's page
Issue.record
Records a failure unconditionally, for places where no condition fits, such as a guard's else branch.
guard case .electric = engine else {
Issue.record("Engine is not electric")
return
}
Swift 6.0, Xcode 16.0 Apple's page
confirmation
Confirms that an event happens while the closure runs. Call the confirmation like a function when the event happens. One time by default.
await confirmation("…") { soldFood in
FoodTruck.shared.eventHandler = { event in
if case .soldFood = event { soldFood() }
}
await Customer().buy(.soup)
}
Swift 6.0, Xcode 16.0 Apple's page
confirmation(expectedCount: 10...)
expectedCount can be a number or a range with a lower bound, such as 10... (at least ten) or 0..<1000.
await confirmation("…", expectedCount: 10...) { soldFood in
...
}
Swift 6.1, Xcode 16.3 Apple's page
withKnownIssue
Marks failures inside the closure as known, so they do not fail the test. isIntermittent: true allows runs that pass.
withKnownIssue("Grill is out of fuel") {
try FoodTruck.shared.grill.start()
}
withKnownIssue("Grill may need fuel", isIntermittent: true) { ... }
Swift 6.0, Xcode 16.0 Apple's page
.enabled(if:)
Runs the test only when the condition is true; otherwise it is skipped before it starts.
@Test("Ice cream is cold", .enabled(if: Season.current == .summer))
func isCold() async throws { ... }
Swift 6.0, Xcode 16.0 Apple's page
.disabled
Skips the test always, or when the condition is true. The comment shows in the test results.
@Test("Food truck sells burritos", .disabled("We only sell Thai cuisine"))
func sellsBurritos() async throws { ... }
@Suite(.disabled(if: CashRegister.isEmpty))
struct FoodTruckTests { ... }
Swift 6.0, Xcode 16.0 Apple's page
.timeLimit
Fails the test if it runs longer than the limit. Minutes only, at least one minute. On a suite, it applies to each test.
@Test(.timeLimit(.minutes(60)))
func serve100CustomersInOneHour() async { ... }
Swift 6.0, Xcode 16.0 Also needs iOS 16, macOS 13, tvOS 16, watchOS 9. Apple's page
.tags
Labels tests so you can filter and group them. Declare tags in an extension of Tag with @Tag.
extension Tag {
@Tag static var legallyRequired: Self
}
@Test("Vendor's license is valid", .tags(.legallyRequired))
func licenseValid() { ... }
Swift 6.0, Xcode 16.0 Apple's page
.serialized
Runs the tests of a suite (or the cases of a parameterized test) one at a time instead of in parallel.
@Suite(.serialized)
class RefrigeratorTests {
@Test func lightComesOn() throws { ... }
@Test func lightGoesOut() throws { ... }
}
Swift 6.0, Xcode 16.0 Apple's page
.bug
Links a test to a bug report by URL, by ID, or both, with an optional title.
@Test("Food truck engine works", .bug("https://www.example.com/issues/12345"))
func engineWorks() async { ... }
@Test(.bug(id: "12345", "Forgot to buy more napkins"))
func hasNapkins() async { ... }
Swift 6.0, Xcode 16.0 Apple's page
@Test(arguments:)
Runs the test once per value. Each value is a separate test case, so a failure names the input that failed. Cases run in parallel by default.
@Test("All foods available", arguments: Food.allCases)
func foodAvailable(_ food: Food) async throws {
let foodTruck = FoodTruck(selling: food)
#expect(await foodTruck.cook(food))
}
Swift 6.0, Xcode 16.0 Apple's page
async tests
Test functions can be async and throwing, and can await code directly.
@Test func priceLookupYieldsExpectedValue() async {
let mozarellaPrice = await unitPrice(for: .mozarella)
#expect(mozarellaPrice == 3)
}
Swift 6.0, Xcode 16.0 Apple's page
Test.cancel
Ends a running test early without failing it, the replacement for throw XCTSkip.
if drawer.isEmpty {
try Test.cancel("Cash register is empty")
}
Swift 6.3, Xcode 26.4 Apple's page
Attachment.record
Attaches a value to the test results, the replacement for XCTAttachment.
let tortilla = Tortilla(diameter: .large)
Attachment.record(tortilla)
Swift 6.2, Xcode 26.0 Apple's page