Swift/XCTest Testing Skill
Expert-level XCTest patterns for Swift 6 macOS/iOS applications. Specialized for SwiftData, EventKit, SwiftUI, and strict concurrency.
When to Use
Use this skill when:
- - Writing XCTest for Swift 6 applications
- Testing SwiftData models with in-memory containers
- Testing Swift 6 actors and
@MainActor isolation - Testing EventKit integrations
- Testing SwiftUI views and @Observable ViewModels
- Writing performance tests for macOS apps
Core Principles
1. SwiftData Testing Pattern
CODEBLOCK0
2. Swift 6 Actor Testing
CODEBLOCK1
3. Given-When-Then Pattern
CODEBLOCK2
4. Test Organization
CODEBLOCK3
Testing Guidelines
SwiftData Models
- - Always use INLINECODE1
- Mark test classes with INLINECODE2
- Use
try context.save() after mutations - Verify state with
FetchDescriptor and INLINECODE5
Actors & Concurrency
- - Test classes interacting with actors should be INLINECODE6
- Use
await for all actor methods - Test isolation boundaries with
nonisolated tests where appropriate
SwiftData Services
- - Use in-memory mode: INLINECODE9
- Test fetch, create, update, delete operations
- Verify
FetchDescriptor queries with predicates
EventKit Mocking
- - Mock
EKEventStore for isolated testing - Test permission handling scenarios
- Verify
EKReminder to model mapping
SwiftUI Views
- - Use
@Testable import to access internal types - Test
@Observable ViewModel behavior - Test state transitions and side effects
Best Practices
- 1. Isolation: Each test should be independent
- Async-Safety: Use
async/await for all async operations - MainActor: Mark SwiftData tests with INLINECODE16
- Performance: Use
measure blocks for critical paths - Readability: Use Given-When-Then comments
- Organization: Group tests with
// MARK: sections
Performance Testing
CODEBLOCK4
Common Test Patterns
Batch Query Testing
CODEBLOCK5
Predicate Testing
CODEBLOCK6
Running Tests
CODEBLOCK7
Swift/XCTest 测试技能
针对 Swift 6 macOS/iOS 应用程序的专家级 XCTest 模式。专为 SwiftData、EventKit、SwiftUI 和严格并发而设计。
使用时机
在以下情况下使用此技能:
- - 为 Swift 6 应用程序编写 XCTest
- 使用内存容器测试 SwiftData 模型
- 测试 Swift 6 参与者和 @MainActor 隔离
- 测试 EventKit 集成
- 测试 SwiftUI 视图和 @Observable ViewModel
- 为 macOS 应用编写性能测试
核心原则
1. SwiftData 测试模式
swift
import SwiftData
import XCTest
@MainActor
final class ModelTests: XCTestCase {
var container: ModelContainer!
var context: ModelContext!
override func setUp() async throws {
try await super.setUp()
// 使用内存配置进行隔离测试
let config = ModelConfiguration(isStoredInMemoryOnly: true)
container = try ModelContainer(for: YourModel.self, configurations: config)
context = container.mainContext
}
override func tearDown() async throws {
container = nil
context = nil
try await super.tearDown()
}
}
2. Swift 6 参与者测试
swift
@MainActor
final class ServiceTests: XCTestCase {
var service: YourActor!
override func setUp() async throws {
try await super.setUp()
service = YourActor()
}
func testActorMethod() async throws {
// 参与者隔离测试与异步操作自然配合
let result = try await service.method()
XCTAssertEqual(result, expected)
}
}
3. 给定-当-则模式
swift
func testFeature() async throws {
// 给定:设置初始状态
let task = service.createTask(title: 测试)
// 当:执行操作
task.complete()
// 则:验证结果
XCTAssertTrue(task.isCompleted)
}
4. 测试组织
swift
@MainActor
final class FeatureTests: XCTestCase {
// MARK: - 属性
// 测试依赖
// MARK: - 设置与清理
// setUp/tearDown 方法
// MARK: - 单元测试
// 隔离测试
// MARK: - 集成测试
// 跨组件测试
// MARK: - 边界情况
// 边界和错误条件
// MARK: - 性能测试
// 性能基准测试
}
测试指南
SwiftData 模型
- - 始终使用 ModelConfiguration(isStoredInMemoryOnly: true)
- 使用 @MainActor 标记测试类
- 在变更后使用 try context.save()
- 使用 FetchDescriptor 和 #Predicate 验证状态
参与者与并发
- - 与参与者交互的测试类应为 @MainActor
- 对所有参与者方法使用 await
- 在适当情况下使用 nonisolated 测试隔离边界
SwiftData 服务
- - 使用内存模式:YourService(inMemory: true)
- 测试获取、创建、更新、删除操作
- 使用谓词验证 FetchDescriptor 查询
EventKit 模拟
- - 模拟 EKEventStore 进行隔离测试
- 测试权限处理场景
- 验证 EKReminder 到模型的映射
SwiftUI 视图
- - 使用 @Testable import 访问内部类型
- 测试 @Observable ViewModel 行为
- 测试状态转换和副作用
最佳实践
- 1. 隔离性:每个测试应独立运行
- 异步安全:对所有异步操作使用 async/await
- MainActor:使用 @MainActor 标记 SwiftData 测试
- 性能:对关键路径使用 measure 代码块
- 可读性:使用给定-当-则注释
- 组织性:使用 // MARK: 部分对测试进行分组
性能测试
swift
func testPerformance() async throws {
measure {
// 需要测量的代码
_ = service.process(data: largeDataSet)
}
}
常见测试模式
批量查询测试
swift
func testBatchFetchEfficiency() async throws {
let ids = (0..<100).map { ID-\($0) }
let start = Date()
let results = service.fetch(by: ids)
let duration = Date().timeIntervalSince(start)
XCTAssertEqual(results.count, 100)
XCTAssertLessThan(duration, 0.5, 批量查询应快速完成)
}
谓词测试
swift
func testPredicateFiltering() async throws {
let descriptor = FetchDescriptor
(
predicate: #Predicate { $0.isDirty == true }
)
let results = try context.fetch(descriptor)
XCTAssertEqual(results.count, expectedCount)
}
运行测试
bash
运行所有测试
xcodebuild test -scheme YourApp -destination platform=macOS
运行特定测试
xcodebuild test -scheme YourApp -destination platform=macOS \
-only-testing:YourAppTests/FeatureTests/testMethod
运行并输出性能结果
xcodebuild test -scheme YourApp -destination platform=macOS \
-resultBundlePath ~/TestResults.xcresult