Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Swift Testing

ASecurity

Write, migrate, and debug tests using Apple's Swift Testing framework (@Test, #expect, parameterized tests, traits). Use when the user mentions Swift Testing, @Test macro, #expect, parameterized tests, test traits, or migrating from XCTest.

22 stars
0 votes
0 copies
0 views
Added 9/20/2026
testinggoswiftbashtestinggitapidatabase

Works with

cliapi

Security Analysis

A100/100

Scanned 9/20/2026

Install to Claude Code

$npx -y skills add lev-os/agents --skill swift-testing --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Swift Testing?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Swift Testing
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/lev-os-swift-testing/badge)](https://www.skillsdirectory.com/skills/lev-os-swift-testing)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: swift-testing
description: Write, migrate, and debug tests using Apple's Swift Testing framework (@Test, #expect, parameterized tests, traits). Use when the user mentions Swift Testing, @Test macro, #expect, parameterized tests, test traits, or migrating from XCTest.
---

# Swift Testing Framework

Apple's modern testing framework replacing XCTest for unit tests. Ships with Xcode 16+ and Swift 6.

## Quick Reference

```swift
import Testing

@Test func basicTest() {
    #expect(2 + 2 == 4)
}

@Test("User can log in with valid credentials")
func loginWithValidCredentials() async throws {
    let result = try await AuthService.login(user: "test", pass: "valid")
    #expect(result.isSuccess)
}
```

## Core Macros

### @Test - Define a test

```swift
// Basic test
@Test func simpleTest() { }

// With display name
@Test("Validates email format correctly")
func emailValidation() { }

// Async test
@Test func asyncOperation() async throws { }

// With traits (see Traits section)
@Test(.enabled(if: ProcessInfo.processInfo.environment["CI"] != nil))
func ciOnlyTest() { }
```

### #expect - Assert conditions

```swift
// Boolean expectation
#expect(value == expected)
#expect(array.isEmpty)
#expect(result != nil)

// With custom message
#expect(count > 0, "Count should be positive")

// Throwing expectation
#expect(throws: ValidationError.self) {
    try validator.validate(invalidInput)
}

// Specific error expectation
#expect(throws: NetworkError.timeout) {
    try await client.fetch(slowEndpoint)
}

// No throw expectation
#expect(throws: Never.self) {
    try safeOperation()
}
```

### #require - Fatal assertions

```swift
// Unwrap optionals (test fails immediately if nil)
let user = try #require(await fetchUser(id: 123))
#expect(user.name == "Alice")

// Boolean requirement (test fails immediately if false)
try #require(database.isConnected)
try #require(file.exists, "Test fixture missing")
```

## Parameterized Tests

Run the same test with multiple inputs:

```swift
@Test(arguments: ["hello", "world", "swift"])
func stringIsNotEmpty(input: String) {
    #expect(!input.isEmpty)
}

@Test(arguments: [
    (2, 3, 5),
    (0, 0, 0),
    (-1, 1, 0),
    (100, 200, 300)
])
func addition(a: Int, b: Int, expected: Int) {
    #expect(a + b == expected)
}

// Zip two collections (paired arguments)
@Test(arguments: zip(["a", "b"], [1, 2]))
func pairedTest(letter: String, number: Int) {
    #expect(!letter.isEmpty)
    #expect(number > 0)
}

// Cartesian product (all combinations)
@Test(arguments: ["light", "dark"], ["iPhone", "iPad"])
func themeDeviceMatrix(theme: String, device: String) {
    // Runs 4 times: light+iPhone, light+iPad, dark+iPhone, dark+iPad
}
```

## Traits

Modify test behavior with traits:

```swift
// Disabled test
@Test(.disabled("Known bug: #123"))
func brokenFeature() { }

// Conditional execution
@Test(.enabled(if: ProcessInfo.processInfo.environment["LIVE_TESTS"] != nil))
func liveAPITest() { }

// Bug reference
@Test(.bug("https://github.com/org/repo/issues/456"))
func workaroundTest() { }

// Tags for filtering
@Test(.tags(.ui, .slow))
func renderingTest() { }

// Time limit
@Test(.timeLimit(.minutes(2)))
func longRunningTest() async { }

// Serial execution (no parallelism)
@Test(.serialized)
func databaseMigrationTest() { }

// Combine traits
@Test(
    "Network timeout handling",
    .tags(.network),
    .timeLimit(.seconds(30)),
    .bug("https://example.com/issue/789", "Flaky on CI")
)
func timeoutTest() async throws { }
```

### Custom Tags

```swift
extension Tag {
    @Tag static var ui: Self
    @Tag static var slow: Self
    @Tag static var network: Self
    @Tag static var integration: Self
}

@Test(.tags(.ui, .slow))
func animationTest() { }
```

## Test Suites (@Suite)

Group related tests:

```swift
@Suite("User Authentication")
struct AuthTests {
    @Test func loginSucceeds() { }
    @Test func loginFailsWithBadPassword() { }
    @Test func logoutClearsSession() { }
}

// Nested suites
@Suite struct NetworkTests {
    @Suite struct RequestTests {
        @Test func getRequest() { }
        @Test func postRequest() { }
    }

    @Suite struct ResponseTests {
        @Test func parseJSON() { }
        @Test func handleError() { }
    }
}

// Suite-level traits (apply to all tests)
@Suite(.serialized)
struct DatabaseTests {
    @Test func migration() { }
    @Test func rollback() { }
}
```

## Setup and Teardown

```swift
@Suite struct ViewModelTests {
    var viewModel: ViewModel!

    // Per-test setup (init runs before each test)
    init() {
        viewModel = ViewModel()
    }

    // Per-test teardown
    deinit {
        viewModel = nil
    }

    @Test func initialState() {
        #expect(viewModel.items.isEmpty)
    }
}

// Async setup
@Suite struct AsyncSetupTests {
    var database: Database

    init() async throws {
        database = try await Database.connect()
    }
}
```

## Confirmation (Async Event Verification)

Wait for async events/callbacks:

```swift
@Test func notificationReceived() async {
    await confirmation { confirm in
        NotificationCenter.default.addObserver(
            forName: .userLoggedIn,
            object: nil,
            queue: .main
        ) { _ in
            confirm()
        }

        await loginUser()
    }
}

// Expected count
@Test func multipleCallbacks() async {
    await confirmation(expectedCount: 3) { confirm in
        for _ in 0..<3 {
            asyncOperation { confirm() }
        }
    }
}
```

## Migrating 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)` |
| `XCTAssertThrowsError(...)` | `#expect(throws: Error.self) { }` |
| `XCTUnwrap(optional)` | `try #require(optional)` |
| `override func setUp()` | `init()` |
| `override func tearDown()` | `deinit` |
| `setUpWithError() async` | `init() async throws` |
| `expectation(description:)` | `await confirmation { }` |

### Migration Example

**Before (XCTest):**
```swift
class UserServiceTests: XCTestCase {
    var service: UserService!

    override func setUp() {
        super.setUp()
        service = UserService()
    }

    func testFetchUserReturnsUser() async throws {
        let user = try await service.fetch(id: 1)
        XCTAssertEqual(user.name, "Alice")
        XCTAssertNotNil(user.email)
    }

    func testFetchInvalidUserThrows() async {
        do {
            _ = try await service.fetch(id: -1)
            XCTFail("Expected error")
        } catch {
            XCTAssertTrue(error is UserError)
        }
    }
}
```

**After (Swift Testing):**
```swift
@Suite struct UserServiceTests {
    let service = UserService()

    @Test func fetchUserReturnsUser() async throws {
        let user = try await service.fetch(id: 1)
        #expect(user.name == "Alice")
        #expect(user.email != nil)
    }

    @Test func fetchInvalidUserThrows() async {
        #expect(throws: UserError.self) {
            try await service.fetch(id: -1)
        }
    }
}
```

## Running Tests

### Xcode
- Cmd+U: Run all tests
- Click diamond in gutter: Run single test
- Test Navigator (Cmd+6): Browse and run

### Command Line
```bash
# Run all tests
swift test

# Run specific test
swift test --filter "UserServiceTests/fetchUser"

# Run tagged tests
swift test --filter ".tags(.network)"

# Parallel execution (default)
swift test --parallel

# Serial execution
swift test --no-parallel
```

## Best Practices

1. **Use descriptive names** - `@Test("Login fails with expired token")` over `@Test func testLoginFail()`

2. **Prefer #expect over #require** - Use `#require` only when subsequent assertions depend on the unwrapped value

3. **Parameterize repetitive tests** - Don't copy-paste tests with different inputs

4. **Tag for CI filtering** - Use `.tags(.slow)` for tests to skip in fast feedback loops

5. **Keep suites focused** - One suite per logical unit (ViewModel, Service, etc.)

6. **Avoid shared mutable state** - Struct suites with `init()` > class with setUp()

## Common Gotchas

- **Mixing frameworks**: Swift Testing and XCTest can coexist but don't share state
- **No setUp/tearDown**: Use `init`/`deinit` instead (or async `init`)
- **Parallel by default**: Tests run concurrently unless `.serialized` applied
- **#expect vs #require**: `#expect` logs and continues; `#require` halts the test
- **Confirmation timeout**: Default is 60 seconds; use `timeout:` parameter for slower operations

Attribution

lev-oslev-os
View sourceMore from lev-os →
SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Related Skills

Screen Reader Testing

Practical guide to testing web applications with screen readers for comprehensive accessibility validation.

393431 votes

Python Testing

使用pytest、TDD方法、夹具、模拟、参数化和覆盖率要求的Python测试策略。

2456590 votes

Tdd Workflow

在编写新功能、修复错误或重构代码时使用此技能。强制执行测试驱动开发,包含单元测试、集成测试和端到端测试,覆盖率超过80%。

2456590 votes

Springboot Tdd

使用JUnit 5、Mockito、MockMvc、Testcontainers和JaCoCo进行Spring Boot的测试驱动开发。适用于添加功能、修复错误或重构时。

2456590 votes

Eval Harness

克劳德代码会话的正式评估框架,实施评估驱动开发(EDD)原则

2456590 votes
View all in testing →