testing-swift
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSwift Testing Framework
Swift Testing 框架
Modern testing with , , and . Replaces XCTest for new projects.
@Test#expect@Suite借助、和实现现代化测试。可在新项目中替代XCTest。
@Test#expect@SuiteCritical Constraints
关键约束
- ❌ DO NOT use in Swift Testing → ✅ Use
XCTAssertEqual#expect(a == b) - ❌ DO NOT use naming convention → ✅ Use
func testSomething()@Test func something() - ❌ DO NOT subclass → ✅ Use
XCTestCaseor plain@Suite structfunctions@Test - ❌ DO NOT use → ✅ Use
XCTAssertThrowsError#expect(throws:) { try something() } - ❌ DO NOT use → ✅ Use
setUp/tearDownoninit/deinitstruct or actor@Suite
- ❌ 请勿在Swift Testing中使用→ ✅ 请使用
XCTAssertEqual#expect(a == b) - ❌ 请勿使用命名规范 → ✅ 请使用
func testSomething()@Test func something() - ❌ 请勿继承→ ✅ 请使用
XCTestCase或直接使用@Suite struct函数@Test - ❌ 请勿使用→ ✅ 请使用
XCTAssertThrowsError#expect(throws:) { try something() } - ❌ 请勿使用→ ✅ 请在
setUp/tearDown结构体或actor中使用@Suiteinit/deinit
Basic Test
基础测试
swift
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")
}swift
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进行测试组织
swift
@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)
}
}swift
@Suite("Shopping List Tests")
struct ShoppingListTests {
var list: ShoppingList
init() {
list = ShoppingList() // 替代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
参数化测试
swift
@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)
}swift
@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)
}
// 使用枚举
enum Priority: CaseIterable { case low, medium, high }
@Test("All priorities have colors", arguments: Priority.allCases)
func priorityColor(priority: Priority) {
#expect(priority.color != nil)
}Expectations
断言(Expectations)
swift
// 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()
}swift
// 相等断言
#expect(result == expected)
// 布尔断言
#expect(user.isActive)
#expect(!list.isEmpty)
// 可选类型断言
#expect(user.name != nil)
let name = try #require(user.name) // 解包失败则测试终止
// 异常断言
#expect(throws: ValidationError.self) {
try validator.validate(invalidInput)
}
// 指定类型异常断言
#expect {
try parser.parse("")
} throws: { error in
guard let parseError = error as? ParseError else { return false }
return parseError.code == .emptyInput
}
// 无异常断言
#expect(throws: Never.self) {
try safeOperation()
}Testing Async Code
异步代码测试
swift
@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)
}swift
@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
@Observable 模型测试
swift
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)
}swift
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)
确认机制(用于事件/回调)
swift
@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()
}
}swift
@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)
}
}
// 指定确认次数
await confirmation("Multiple events", expectedCount: 3) { confirm in
for _ in 0..<3 {
EventEmitter.emit(.tick)
confirm()
}
}Test Traits
测试特性(Test Traits)
swift
@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
}swift
@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迁移
| XCTest | Swift Testing |
|---|---|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| XCTest | Swift Testing |
|---|---|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |