testing-swift
Swift Testing Framework
Modern testing with @Test, #expect, and @Suite. Replaces XCTest for new projects.
Critical Constraints
- ❌ DO NOT use
XCTAssertEqualin Swift Testing → ✅ Use#expect(a == b) - ❌ DO NOT use
func testSomething()naming convention → ✅ Use@Test func something() - ❌ DO NOT subclass
XCTestCase→ ✅ Use@Suite structor plain@Testfunctions - ❌ DO NOT use
XCTAssertThrowsError→ ✅ Use#expect(throws:) { try something() } - ❌ DO NOT use
setUp/tearDown→ ✅ Useinit/deiniton@Suitestruct or actor
Basic Test
import Testing
@Test("Adding items increases count")
func addItem() {
var list = ShoppingList()
list.add("Milk")
#expect(list.items.count == 1)
#expect(list.items.first == "Milk")
}
@Suite for Organization
@Suite("Shopping List Tests")
struct ShoppingListTests {
var list: ShoppingList
init() {
list = ShoppingList() // Replaces setUp()
}
@Test func addItem() {
list.add("Bread")
#expect(list.items.contains("Bread"))
}
@Test func removeItem() {
list.add("Bread")
list.remove("Bread")
#expect(list.items.isEmpty)
}
}
Parameterized Tests
@Test("Validates email format", arguments: [
("user@example.com", true),
("invalid", false),
("a@b.c", true),
("@missing.com", false),
])
func emailValidation(email: String, isValid: Bool) {
#expect(EmailValidator.isValid(email) == isValid)
}
// With enums
enum Priority: CaseIterable { case low, medium, high }
@Test("All priorities have colors", arguments: Priority.allCases)
func priorityColor(priority: Priority) {
#expect(priority.color != nil)
}
Expectations
// Equality
#expect(result == expected)
// Boolean
#expect(user.isActive)
#expect(!list.isEmpty)
// Optional
#expect(user.name != nil)
let name = try #require(user.name) // Unwrap or fail
// Throws
#expect(throws: ValidationError.self) {
try validator.validate(invalidInput)
}
// Specific error
#expect {
try parser.parse("")
} throws: { error in
guard let parseError = error as? ParseError else { return false }
return parseError.code == .emptyInput
}
// No throw
#expect(throws: Never.self) {
try safeOperation()
}
Testing Async Code
@Test func asyncFetch() async throws {
let service = DataService()
let items = try await service.fetchItems()
#expect(!items.isEmpty)
}
@Test(.timeLimit(.minutes(1)))
func longRunningOperation() async throws {
let result = try await processor.processLargeFile()
#expect(result.isComplete)
}
Testing @Observable Models
import Testing
import Observation
@Test func modelUpdates() {
let model = CounterModel()
#expect(model.count == 0)
model.increment()
#expect(model.count == 1)
model.reset()
#expect(model.count == 0)
}
@Test func asyncModelLoading() async {
let model = ItemListModel()
await model.loadItems()
#expect(!model.items.isEmpty)
#expect(!model.isLoading)
}
Confirmation (for Events/Callbacks)
@Test func notificationFires() async {
await confirmation("Callback received") { confirm in
let observer = EventObserver { event in
#expect(event.type == .update)
confirm()
}
observer.startListening()
EventEmitter.emit(.update)
}
}
// Expected count
await confirmation("Multiple events", expectedCount: 3) { confirm in
for _ in 0..<3 {
EventEmitter.emit(.tick)
confirm()
}
}
Test Traits
@Test(.disabled("Flaky on CI"))
func unreliableTest() { }
@Test(.bug("https://github.com/org/repo/issues/42", "Crashes on empty input"))
func knownBug() { }
@Test(.timeLimit(.seconds(5)))
func mustBeFast() async { }
@Test(.tags(.performance))
func benchmarkSort() { }
extension Tag {
@Tag static var performance: Self
@Tag static var integration: Self
}
Migration from XCTest
| XCTest | Swift Testing |
|---|---|
class FooTests: XCTestCase |
@Suite struct FooTests |
func testBar() |
@Test func bar() |
XCTAssertEqual(a, b) |
#expect(a == b) |
XCTAssertTrue(x) |
#expect(x) |
XCTAssertNil(x) |
#expect(x == nil) |
XCTUnwrap(x) |
try #require(x) |
XCTAssertThrowsError |
#expect(throws:) { } |
setUp() |
init() |
tearDown() |
deinit |
XCTSkip |
try #require(condition) |
References
More from makgunay/claude-swift-skills
swiftui-core
Core SwiftUI patterns for macOS and iOS development including navigation (NavigationSplitView, NavigationStack), state management (@State, @Binding, @Environment, @Bindable with @Observable), the new customizable toolbar system (toolbar IDs, ToolbarSpacer, DefaultToolbarItem, searchToolbarBehavior, matchedTransitionSource, sharedBackgroundVisibility), styled text editing (TextEditor with AttributedString, AttributedTextSelection, transformAttributes, textFormattingDefinition), and layout patterns. Use when building any SwiftUI view, implementing navigation, managing state, creating toolbars, or building rich text editors. Corrects common LLM errors like using deprecated NavigationView, wrong state wrappers, and outdated toolbar APIs.
14global-hotkeys
System-wide keyboard shortcut registration on macOS using NSEvent monitoring (simple, app-level) and Carbon EventHotKey API (reliable, system-wide). Covers NSEvent.addGlobalMonitorForEvents and addLocalMonitorForEvents, CGEvent tap for keystroke simulation, Carbon RegisterEventHotKey for system-wide hotkeys, modifier flag handling (.deviceIndependentFlagsMask), common key code mappings, debouncing, Accessibility permission requirements (AXIsProcessTrusted), and SwiftUI .onKeyPress for in-app shortcuts. Use when implementing global keyboard shortcuts, hotkey-triggered panels, or system-wide key event monitoring.
11swiftui-webkit
Native SwiftUI WebKit integration with the new WebView struct and WebPage observable class. Covers WebView creation from URLs, WebPage for navigation control and state management, JavaScript execution (callJavaScript with arguments and content worlds), custom URL scheme handlers, navigation management (load, reload, back/forward), navigation decisions, text search (findNavigator), content capture (snapshots, PDF generation, web archives), and configuration (data stores, user agents, JS permissions). Use when embedding web content in SwiftUI apps instead of the old WKWebView + UIViewRepresentable/NSViewRepresentable bridge pattern. This is a brand new API — do NOT use the old WKWebView wrapping approach.
10liquid-glass
Comprehensive guide to Apple's Liquid Glass design system introduced in macOS 26, iOS 26, and across all Apple platforms. Covers SwiftUI (.glassEffect(), GlassEffectContainer, .interactive(), .tint(), glassEffectID morphing, .buttonStyle(.glass), .buttonStyle(.glassProminent), glassEffectUnion), AppKit (NSGlassEffectView, NSGlassEffectContainerView), UIKit (UIGlassEffect, UIGlassContainerEffect, UIScrollEdgeEffect), and WidgetKit (accented rendering mode, widgetAccentable). Use whenever building UI with the new Apple design language, adopting glass effects, styling buttons or toolbars, or creating modern macOS/iOS interfaces. Always consult this skill when asked about new Apple design.
10tech-stack-validator
Validates and recommends technology stacks for native macOS/iOS app projects against PRD and architecture requirements. Reads the PRD and architecture documents (or gathers requirements interactively), then systematically checks every technology choice for: OS version availability, framework capability gaps, performance feasibility, distribution compatibility (sandbox vs direct), API deprecation risks, dependency conflicts, and timeline realism for the team size. Produces a structured validation report with go/no-go verdicts, risk flags, and alternative recommendations. Use when user says things like 'validate my tech stack', 'check if this architecture works', 'what should I build this with', 'is SwiftData the right choice', 'can I ship this on the App Store', 'review my architecture', or before starting implementation of any PRD. Also use when migrating between tech stacks or evaluating whether to adopt a new framework.
9swift-lang
Swift 6.2 language patterns and critical corrections for LLM code generation. Covers the concurrency paradigm shift (default MainActor isolation, @concurrent for background work, isolated conformances, nonisolated opt-out), @Observable vs ObservableObject, structured concurrency, modern error handling, property wrappers, InlineArray, Span, and value generics. Use whenever generating Swift code, especially async/concurrent code, class/struct design, or performance-critical paths. This skill prevents the most common LLM mistakes in Swift code generation.
8