swift-testing by bocato/swift-testing-agent-skill
npx skills add https://github.com/bocato/swift-testing-agent-skill --skill swift-testing本技能提供关于 Swift Testing 的专家指导,涵盖现代 Swift Testing 框架、测试替身(模拟对象、桩、间谍)、夹具、集成测试、快照测试以及从 XCTest 迁移。使用此技能帮助开发者遵循 F.I.R.S.T. 原则和 Arrange-Act-Assert 模式编写可靠、可维护的测试。
@Test、#expect、#require、@Suite),而非 XCTest。#if DEBUG 将夹具放置在靠近模型的位置,而不是在测试目标中。#if DEBUG 将测试替身放置在靠近接口的位置,而不是在测试目标中。#expect 进行软断言(失败后继续执行),使用 进行硬断言(失败后停止执行)。广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
#require当开发者需要测试指导时,请遵循此决策树:
从头开始使用 Swift Testing?
references/test-organization.md 了解套件、标签、特性references/async-testing.md 了解异步测试模式需要创建测试数据?
references/fixtures.md 了解夹具模式和放置位置references/test-doubles.md 了解模拟/桩/间谍模式测试多个输入?
references/parameterized-tests.md 了解参数化测试测试模块交互?
references/integration-testing.md 了解集成测试模式测试 UI 回归?
references/snapshot-testing.md 了解快照测试设置测试数据结构或状态?
references/dump-snapshot-testing.md 了解基于文本的快照测试从 XCTest 迁移?
references/migration-xctest.md 获取迁移指南references/migration-xctest.md 进行从 XCTest 到 Swift Testing 的迁移references/async-testing.md 了解异步模式、确认、超时references/test-doubles.md 使用正确的模拟references/fixtures.md 了解使用固定日期的夹具模式references/parameterized-tests.md 进行参数化测试references/integration-testing.md 了解集成测试模式import Testing
@Test func basicTest() {
#expect(1 + 1 == 2)
}
@Test("Adding items increases cart count")
func addItem() {
let cart = Cart()
cart.add(item)
#expect(cart.count == 1)
}
@Test func asyncOperation() async throws {
let result = try await service.fetch()
#expect(result.isValid)
}
使用清晰的阶段组织每个测试:
@Test func calculateTotal() {
// Given
let cart = ShoppingCart()
cart.add(Item(price: 10))
cart.add(Item(price: 20))
// When
let total = cart.calculateTotal()
// Then
#expect(total == 30)
}
失败后继续执行测试:
@Test func multipleExpectations() {
let user = User(name: "Alice", age: 30)
#expect(user.name == "Alice") // 如果失败,测试继续
#expect(user.age == 30) // 此断言仍会运行
}
失败时停止测试执行:
@Test func requireExample() throws {
let user = try #require(fetchUser()) // 如果为 nil 则停止
#expect(user.name == "Alice")
}
@Test func throwsError() {
#expect(throws: ValidationError.self) {
try validate(invalidInput)
}
}
@Test func throwsSpecificError() {
#expect(throws: ValidationError.emptyField) {
try validate("")
}
}
| 原则 | 描述 | 应用 |
|---|---|---|
| 快速 | 测试在毫秒级执行 | 模拟昂贵的操作 |
| 隔离 | 测试互不依赖 | 每个测试使用新实例 |
| 可重复 | 每次结果相同 | 模拟日期、网络、外部依赖 |
| 自我验证 | 自动报告通过/失败 | 使用 #expect,绝不依赖 print() |
| 及时 | 与代码同步编写测试 | 使用参数化测试处理边界情况 |
| 类型 | 目的 | 验证方式 |
|---|---|---|
| Dummy | 填充参数,从不使用 | 不适用 |
| Fake | 带有捷径的工作实现 | 状态 |
| Stub | 提供预设答案 | 状态 |
| Spy | 记录调用以供验证 | 状态 |
| SpyingStub | Stub + Spy 组合(最常见) | 状态 |
| Mock | 预编程的期望,自我验证 | 行为 |
重要提示:Swift 社区通常所说的 "Mock" 通常是 SpyingStub。
有关详细模式,请参阅 references/test-doubles.md。
将测试替身放置在靠近接口的位置,而不是在测试目标中:
// 在 PersonalRecordsCore-Interface/Sources/...
public protocol PersonalRecordsRepositoryProtocol: Sendable {
func getAll() async throws -> [PersonalRecord]
func save(_ record: PersonalRecord) async throws
}
#if DEBUG
public final class PersonalRecordsRepositorySpyingStub: PersonalRecordsRepositoryProtocol {
// Spy: 捕获的调用
public private(set) var savedRecords: [PersonalRecord] = []
// Stub: 可配置的响应
public var recordsToReturn: [PersonalRecord] = []
public var errorToThrow: Error?
public func getAll() async throws -> [PersonalRecord] {
if let error = errorToThrow { throw error }
return recordsToReturn
}
public func save(_ record: PersonalRecord) async throws {
if let error = errorToThrow { throw error }
savedRecords.append(record)
}
}
#endif
将夹具放置在靠近模型的位置:
// 在 Sources/Models/PersonalRecord.swift
public struct PersonalRecord: Equatable, Sendable {
public let id: UUID
public let weight: Double
// ...
}
#if DEBUG
extension PersonalRecord {
public static func fixture(
id: UUID = UUID(),
weight: Double = 100.0
// ... 所有属性的默认值
) -> PersonalRecord {
PersonalRecord(id: id, weight: weight)
}
}
#endif
有关详细模式,请参阅 references/fixtures.md。
+-------------+
| UI Tests | 5% - 端到端流程
| (E2E) |
+-------------+
| Integration | 15% - 模块交互
| Tests |
+-------------+
| Unit | 80% - 独立组件
| Tests |
+-------------+
根据具体主题需要加载这些文件:
test-organization.md - 套件、标签、特性、并行执行parameterized-tests.md - 高效测试多个输入async-testing.md - 异步模式、确认、超时、取消migration-xctest.md - 完整的 XCTest 到 Swift Testing 迁移指南test-doubles.md - 包含示例的完整分类法(Dummy、Fake、Stub、Spy、SpyingStub、Mock)fixtures.md - 夹具模式、放置位置和最佳实践integration-testing.md - 模块交互测试模式snapshot-testing.md - 使用 SnapshotTesting 库进行 UI 回归测试dump-snapshot-testing.md - 用于数据结构的基于文本的快照测试#if DEBUG 保护#if DEBUG 保护每周安装数
42
仓库
GitHub 星标数
71
首次出现
Jan 27, 2026
安全审计
安装于
codex37
cursor35
gemini-cli32
opencode31
github-copilot30
claude-code28
This skill provides expert guidance on Swift Testing, covering the modern Swift Testing framework, test doubles (mocks, stubs, spies), fixtures, integration testing, snapshot testing, and migration from XCTest. Use this skill to help developers write reliable, maintainable tests following F.I.R.S.T. principles and Arrange-Act-Assert patterns.
@Test, #expect, #require, @Suite) for all new tests, not XCTest.#if DEBUG, not in test targets.#if DEBUG, not in test targets.#expect for soft assertions (continue on failure) and #require for hard assertions (stop on failure).When a developer needs testing guidance, follow this decision tree:
Starting fresh with Swift Testing?
references/test-organization.md for suites, tags, traitsreferences/async-testing.md for async test patternsNeed to create test data?
references/fixtures.md for fixture patterns and placementreferences/test-doubles.md for mock/stub/spy patternsTesting multiple inputs?
references/parameterized-tests.md for parameterized testingTesting module interactions?
references/integration-testing.md for integration test patternsreferences/migration-xctest.md for XCTest to Swift Testing migrationreferences/async-testing.md for async patterns, confirmation, timeoutsreferences/test-doubles.mdreferences/fixtures.md for fixture patterns with fixed datesreferences/parameterized-tests.md for parameterized testingreferences/integration-testing.md for integration test patternsimport Testing
@Test func basicTest() {
#expect(1 + 1 == 2)
}
@Test("Adding items increases cart count")
func addItem() {
let cart = Cart()
cart.add(item)
#expect(cart.count == 1)
}
@Test func asyncOperation() async throws {
let result = try await service.fetch()
#expect(result.isValid)
}
Structure every test with clear phases:
@Test func calculateTotal() {
// Given
let cart = ShoppingCart()
cart.add(Item(price: 10))
cart.add(Item(price: 20))
// When
let total = cart.calculateTotal()
// Then
#expect(total == 30)
}
Continues test execution after failure:
@Test func multipleExpectations() {
let user = User(name: "Alice", age: 30)
#expect(user.name == "Alice") // If fails, test continues
#expect(user.age == 30) // This still runs
}
Stops test execution on failure:
@Test func requireExample() throws {
let user = try #require(fetchUser()) // Stops if nil
#expect(user.name == "Alice")
}
@Test func throwsError() {
#expect(throws: ValidationError.self) {
try validate(invalidInput)
}
}
@Test func throwsSpecificError() {
#expect(throws: ValidationError.emptyField) {
try validate("")
}
}
| Principle | Description | Application |
|---|---|---|
| Fast | Tests execute in milliseconds | Mock expensive operations |
| Isolated | Tests don't depend on each other | Fresh instance per test |
| Repeatable | Same result every time | Mock dates, network, external deps |
| Self-Validating | Auto-report pass/fail | Use #expect, never rely on print() |
| Timely | Write tests alongside code | Use parameterized tests for edge cases |
Per Martin Fowler's definition:
| Type | Purpose | Verification |
|---|---|---|
| Dummy | Fill parameters, never used | N/A |
| Fake | Working implementation with shortcuts | State |
| Stub | Provides canned answers | State |
| Spy | Records calls for verification | State |
| SpyingStub | Stub + Spy combined (most common) | State |
| Mock | Pre-programmed expectations, self-verifies | Behavior |
Important : What Swift community calls "Mock" is usually a SpyingStub.
For detailed patterns, see references/test-doubles.md.
Place test doubles close to the interface , not in test targets:
// In PersonalRecordsCore-Interface/Sources/...
public protocol PersonalRecordsRepositoryProtocol: Sendable {
func getAll() async throws -> [PersonalRecord]
func save(_ record: PersonalRecord) async throws
}
#if DEBUG
public final class PersonalRecordsRepositorySpyingStub: PersonalRecordsRepositoryProtocol {
// Spy: Captured calls
public private(set) var savedRecords: [PersonalRecord] = []
// Stub: Configurable responses
public var recordsToReturn: [PersonalRecord] = []
public var errorToThrow: Error?
public func getAll() async throws -> [PersonalRecord] {
if let error = errorToThrow { throw error }
return recordsToReturn
}
public func save(_ record: PersonalRecord) async throws {
if let error = errorToThrow { throw error }
savedRecords.append(record)
}
}
#endif
Place fixtures close to the model :
// In Sources/Models/PersonalRecord.swift
public struct PersonalRecord: Equatable, Sendable {
public let id: UUID
public let weight: Double
// ...
}
#if DEBUG
extension PersonalRecord {
public static func fixture(
id: UUID = UUID(),
weight: Double = 100.0
// ... defaults for all properties
) -> PersonalRecord {
PersonalRecord(id: id, weight: weight)
}
}
#endif
For detailed patterns, see references/fixtures.md.
+-------------+
| UI Tests | 5% - End-to-end flows
| (E2E) |
+-------------+
| Integration | 15% - Module interactions
| Tests |
+-------------+
| Unit | 80% - Individual components
| Tests |
+-------------+
Load these files as needed for specific topics:
test-organization.md - Suites, tags, traits, parallel executionparameterized-tests.md - Testing multiple inputs efficientlyasync-testing.md - Async patterns, confirmation, timeouts, cancellationmigration-xctest.md - Complete XCTest to Swift Testing migration guidetest-doubles.md - Complete taxonomy with examples (Dummy, Fake, Stub, Spy, SpyingStub, Mock)fixtures.md - Fixture patterns, placement, and best practicesintegration-testing.md - Module interaction testing patterns#if DEBUG guards#if DEBUG guardsWeekly Installs
42
Repository
GitHub Stars
71
First Seen
Jan 27, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex37
cursor35
gemini-cli32
opencode31
github-copilot30
claude-code28
测试策略完整指南:单元/集成/E2E测试金字塔与自动化实践
11,200 周安装
注册流程转化率优化指南:提升用户注册完成率的专家建议与最佳实践
298 周安装
AI智能体指令文件重构工具 - 渐进式披露原则优化AGENTS.md/CLAUDE.md文件结构
298 周安装
Ruby on Rails 应用开发指南:构建功能全面的Rails应用,包含模型、控制器、身份验证与最佳实践
298 周安装
Reddit 只读浏览技能 - 安全获取帖子、评论与搜索,助力智能体开发
297 周安装
原生广告投放指南:Taboola/Outbrain平台优化策略、创意测试与预算建议
313 周安装
自主智能体架构指南:从ReAct模式到可靠部署的最佳实践与风险规避
296 周安装
Testing UI for regressions?
references/snapshot-testing.md for snapshot testing setupTesting data structures or state?
references/dump-snapshot-testing.md for text-based snapshot testingMigrating from XCTest?
references/migration-xctest.md for migration guidesnapshot-testing.mddump-snapshot-testing.md - Text-based snapshot testing for data structures