用途
Swift Testing 技能为开发者提供关于现代 Swift Testing 框架的专业指导,涵盖最佳实践、测试模式与具体实现。当开发者提到 Swift Testing、@Test、#expect、#require 等关键词,或需要编写、重构、迁移 Swift 测试时,可使用该技能获得针对性建议。
主要能力
该技能覆盖以下主题:
- 现代 Swift Testing 框架的核心语法与用法,包括 @Test、#expect、#require、@Suite。
- 测试替身(test doubles):按照 Martin Fowler 的分类法,涵盖 Dummy、Fake、Stub、Spy、SpyingStub、Mock。
- Fixtures:测试数据的构造模式与放置位置。
- 集成测试:模块交互的测试模式。
- 快照测试:UI 回归测试与基于文本的快照测试。
- 从 XCTest 迁移到 Swift Testing 的完整指南。
- 异步测试模式、confirmation、超时与取消。
- 参数化测试:高效测试多个输入。
- 测试组织:suites、tags、traits、并行执行。
使用方式
该技能以“决策树”和“分诊优先手册”的方式组织内容,根据开发者当前需求引导到对应的参考文件:
- 刚开始使用 Swift Testing:阅读 test-organization.md 与 async-testing.md。
- 需要创建测试数据:阅读 fixtures.md 与 test-doubles.md。
- 测试多个输入:阅读 parameterized-tests.md。
- 测试模块交互:阅读 integration-testing.md。
- 测试 UI 回归:阅读 snapshot-testing.md。
- 测试数据结构或状态:阅读 dump-snapshot-testing.md。
- 从 XCTest 迁移:阅读 migration-xctest.md。
常见错误对应处理:
- “XCTAssertEqual is unavailable”或需要现代化测试:使用 migration-xctest.md。
- 需要测试异步代码:使用 async-testing.md。
- 测试缓慢或不稳定:检查 F.I.R.S.T. 原则,按 test-doubles.md 使用正确的 mock。
- 需要确定性测试数据:使用 fixtures.md,采用固定日期。
- 需要高效测试多个场景:使用 parameterized-tests.md。
- 需要验证组件交互:使用 integration-testing.md。
核心原则与约定
该技能要求遵循以下规则:
- 所有新测试使用 Swift Testing 框架(@Test、#expect、#require、@Suite),而非 XCTest。
- 测试始终采用清晰的 Arrange-Act-Assert 结构。
- 遵循 F.I.R.S.T. 原则:Fast(快速)、Isolated(隔离)、Repeatable(可重复)、Self-Validating(自验证)、Timely(及时)。
- 使用符合 Martin Fowler 分类法的测试替身术语。
- Fixtures 放在模型附近,使用 #if DEBUG 保护,而非放在测试 target 中。
- 测试替身放在接口附近,使用 #if DEBUG 保护,而非放在测试 target 中。
- 优先使用状态验证而非行为验证,测试更简单、更不易脆弱。
- 使用 #expect 进行软断言(失败后继续),使用 #require 进行硬断言(失败后停止)。
核心语法示例
基本测试:
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)
}
Arrange-Act-Assert 模式:
@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)
}
断言:
- #expect 为软断言,失败后测试继续执行。
- #require 为硬断言,失败后停止测试执行。
错误测试:
@Test func throwsError() {
#expect(throws: ValidationError.self) {
try validate(invalidInput)
}
}
@Test func throwsSpecificError() {
#expect(throws: ValidationError.emptyField) {
try validate("")
}
}
测试替身参考
按照 Martin Fowler 的定义:
- Dummy:填充参数,从不使用,无验证。
- Fake:可工作的实现,带有捷径,状态验证。
- Stub:提供预设答案,状态验证。
- Spy:记录调用以供验证,状态验证。
- SpyingStub:Stub 与 Spy 的组合(最常见),状态验证。
- Mock:预编程期望,自我验证,行为验证。
注意:Swift 社区所称的“Mock”通常是 SpyingStub。
测试替身应放在接口附近,而非测试 target 中,并使用 #if DEBUG 保护。
Fixtures
Fixtures 应放在模型附近,使用 #if DEBUG 保护,并提供合理的默认值。
测试金字塔
- UI 测试(E2E):5%,端到端流程。
- 集成测试:15%,模块交互。
- 单元测试:80%,单个组件。
适用场景
- 编写新的 Swift 测试。
- 将现有 XCTest 测试迁移到 Swift Testing。
- 测试异步代码、参数化输入、模块交互、UI 回归。
- 构造确定性测试数据与测试替身。
- 排查测试缓慢或不稳定的问题。
限制
资料未提供该技能的安装方式、收费模式、支持平台或具体版本要求,这些信息暂未提供。