概述
WWDC 24 祭出的全新单元测试系统着实让苹果开发者们眼前一亮。"原来测试还可以这么爽!?",日渐逼近蟋蟀发型的某位码农如是说。
Swift Testing 在简洁性以及灵活性全面超越老大哥 XCTest 的同时,也让秃头码农们真正见识到了 Swifty 范儿测试的灵魂。
在本篇博文中,您将学到如下内容:
本篇是《用接地气的例子趣谈 WWDC 24 全新的 Swift Testing 入门》系列博文的进阶学习,希望大家喜欢。
那还等什么呢?Let's Testing!!!😉
1. 如何为测试加上"构造"和"析构"器
在以往的 XCTest 测试系统中,我们是用 XCTestCase 派生子类中的特定方法来完成每个测试的初始化和清理操作的:
swift
final class MyUnitTests: XCTestCase {
// 初始化测试
override func setUpWithError() throws {
continueAfterFailure = false
}
// 清理测试
override func tearDownWithError() throws {
}
}
而在新的 Swift Testing 中,我们只需使用类型本就具有的构造和析构器即可。
比如在下面的测试中,我们将所有独立的测试方法一并放到 ModelTests 结构中,然后借助结构的构造器来完成测试的初始化工作:
swift
struct ModelTests {
let container: ModelContainer
// 测试前的所有初始化操作统统进来!!!
init() throws {
let config = ModelConfiguration(isStoredInMemoryOnly: true)
container = try ModelContainer(for: User.self, configurations: config)
}
@Test func verifyBulkImport() throws {
User.bulkImport()
let modelContext = ModelContext(container)
let count = try modelContext.fetchCount(FetchDescriptor<User>())
#expect(count == 100)
}
}
类似的,如果我们需要在测试之后完成一些必要的清理工作,同样可以将上面的结构"升级"为类,然后利用类的析构方法来搞定它们:
swift
class ModelTests {
let container: ModelContainer
init() throws {
let config = ModelConfiguration(isStoredInMemoryOnly: true)
container = try ModelContainer(for: User.self, configurations: config)
}
// 利用类的析构器来将测试之后的一切清理干净!
deinit {
container.deleteAllData()
}
@Test func verifyBulkImport() throws {
User.bulkImport()
let modelContext = ModelContext(container)
let count = try modelContext.fetchCount(FetchDescriptor<User>())
#expect(count == 100)
}
}
如您所见:在 Swift Testing 中我们没有搞任何"特殊行为",仅仅借助结构和类的"原始本能"即可轻松将测试的初始化和清扫工作化为无形,就问大家赞不赞呢?
2. 如何依次串行测试?
在包含海量 Testing 方法的单元测试中,为了达到客观的"公平公正",我们往往需要这些方法随机执行:即每次测试它们的执行顺序都是不确定的。这样做到好处是可以将可能出现的代码依赖关系降到最低。
这还不算完!为了最大化保证测试的"实事求是",我们还需要这些测试的执行可以重叠,即它们可以并发运行。
swift
struct ModelTests {
var model = Model.shared
@Test("测试创建 Itmes", .tags(.createItem))
mutating func createItems() {
print("#1 start")
model.createItems()
#expect(!model.items.isEmpty, "应该成功创建若干 Items!")
print("#1 end")
}
@Test("测试删除所有 Item")
mutating func delItem(){
print("#2 start")
model.createItems()
#expect(!model.items.isEmpty)
model.deleteAllItems()
#expect(model.items.isEmpty, "应该成功删除所有 Items!")
print("#2 end")
}
@Test("无厘头测试")
mutating func noHead(){
print("#3 start")
#expect(true)
print("#3 end")
}
}
在上面的 ModelTests 测试中,多次运行可以发现其中 3 个测试方法的执行顺序皆是变幻无穷。甚至某个方法还未完成,另一个方法就"跃跃欲试"了:
swift
◇ Test run started.
↳ Testing Library Version: 102 (arm64-apple-ios13.0-simulator)
◇ Suite ModelTests started.
◇ Test "测试创建 Itmes" started.
◇ Test "测试删除所有 Item" started.
◇ Test "无厘头测试" started.
#2 start
#3 start
#2 end
#3 end
✔ Test "测试删除所有 Item" passed after 0.001 seconds.
✔ Test "无厘头测试" passed after 0.001 seconds.
#1 start
#1 end
✔ Test "测试创建 Itmes" passed after 0.001 seconds.
✔ Suite ModelTests passed after 0.001 seconds.
✔ Test run with 3 tests passed after 0.001 seconds.
但在某些场景中,我们可能也需要测试方法能够按照它们定义的顺序依次串行执行。这在 Swift Testing 里非常容易,简直轻而易举!
只需使用 @Suite 宏即可优雅的"樽前月下":
更具体的说,在 @Suite 宏的若干 SuiteTrait 中包含一个 serialized 特性,它就是测试里我们那个"真命天子":
还拿上面的 ModelTests 测试结构来说,其中的内容无需做任何改变,只需用 @Suite 宏如此这般修饰它即可:
swift
@Suite(.serialized)
struct ModelTests {...}
再次运行测试可以看到,所有测试方法都会"言听计从"的自上而下串行执行了:
swift
◇ Test run started.
↳ Testing Library Version: 102 (arm64-apple-ios13.0-simulator)
◇ Suite ModelTests started.
◇ Test "测试创建 Itmes" started.
#1 start
#1 end
✔ Test "测试创建 Itmes" passed after 0.001 seconds.
◇ Test "测试删除所有 Item" started.
#2 start
#2 end
✔ Test "测试删除所有 Item" passed after 0.001 seconds.
◇ Test "无厘头测试" started.
#3 start
#3 end
✔ Test "无厘头测试" passed after 0.001 seconds.
✔ Suite ModelTests passed after 0.001 seconds.
✔ Test run with 3 tests passed after 0.001 seconds.
当然如果我们希望的话,还可以利用 @Suite 宏丰富多彩的构造器来让测试更加"银杏化":
swift
@Suite("大熊猫侯佩的大测试", .serialized)
struct ModelTests {...}
现在,相信小伙伴们对 Xcode 16 中崭新的 Swift Testing 都轻车熟路、了如指掌了吧?棒棒哒!💯
更多关于 Swift Testing 测试系统的介绍,请小伙伴们移步如下链接观赏精彩的内容:
- 用接地气的例子趣谈 WWDC 24 全新的 Swift Testing 入门(一)
- 用接地气的例子趣谈 WWDC 24 全新的 Swift Testing 入门(二)
- 用接地气的例子趣谈 WWDC 24 全新的 Swift Testing 入门(三)
想要系统学习 Swift 的小伙伴们,欢迎到我的《Swift语言开发精讲》专栏来逛一逛哦:
总结
在本篇博文中,我们进一步讨论了 WWDC24(Xcode 16)中全新 Swift Testing 的驾驭之道,并用多个轻巧的"栗子"让小伙伴们明白晓畅。
感谢观赏,再会啦!😎