WWDC24(Xcode 16)中全新的 Swift Testing 使用进阶

时间:2024-11-10 12:14:44

在这里插入图片描述

概述

WWDC 24 祭出的全新单元测试系统着实让苹果开发者们眼前一亮。“原来测试还可以这么爽!?”,日渐逼近蟋蟀发型的某位码农如是说。

在这里插入图片描述

Swift Testing 在简洁性以及灵活性全面超越老大哥 XCTest 的同时,也让秃头码农们真正见识到了 Swifty 范儿测试的灵魂。

在本篇博文中,您将学到如下内容:

  • 概述
  • 1. 如何为测试加上“构造”和“析构”器
  • 2. 如何依次串行测试?
  • 总结

本篇是《用接地气的例子趣谈 WWDC 24 全新的 Swift Testing 入门》系列博文的进阶学习,希望大家喜欢。

那还等什么呢?Let‘s Testing!!!????


1. 如何为测试加上“构造”和“析构”器

在以往的 XCTest 测试系统中,我们是用 XCTestCase 派生子类中的特定方法来完成每个测试的初始化和清理操作的:

final class MyUnitTests: XCTestCase {

    // 初始化测试
    override func setUpWithError() throws {
        continueAfterFailure = false

    }

    // 清理测试
    override func tearDownWithError() throws {
    }
}

而在新的 Swift Testing 中,我们只需使用类型本就具有的构造和析构器即可。

比如在下面的测试中,我们将所有独立的测试方法一并放到 ModelTests 结构中,然后借助结构的构造器来完成测试的初始化工作:

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)
    }
}

类似的,如果我们需要在测试之后完成一些必要的清理工作,同样可以将上面的结构“升级”为类,然后利用类的析构方法来搞定它们:

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 方法的单元测试中,为了达到客观的“公平公正”,我们往往需要这些方法随机执行:即每次测试它们的执行顺序都是不确定的。这样做到好处是可以将可能出现的代码依赖关系降到最低。

这还不算完!为了最大化保证测试的“实事求是”,我们还需要这些测试的执行可以重叠,即它们可以并发运行

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 个测试方法的执行顺序皆是变幻无穷。甚至某个方法还未完成,另一个方法就“跃跃欲试”了:

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 宏如此这般修饰它即可:

@Suite(.serialized)
struct ModelTests {...}

再次运行测试可以看到,所有测试方法都会“言听计从”的自上而下串行执行了:

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 宏丰富多彩的构造器来让测试更加“银杏化”:

@Suite("大熊猫侯佩的大测试", .serialized)
struct ModelTests {...}

在这里插入图片描述

现在,相信小伙伴们对 Xcode 16 中崭新的 Swift Testing 都轻车熟路、了如指掌了吧?棒棒哒!????


更多关于 Swift Testing 测试系统的介绍,请小伙伴们移步如下链接观赏精彩的内容:

  • 用接地气的例子趣谈 WWDC 24 全新的 Swift Testing 入门(一)
  • 用接地气的例子趣谈 WWDC 24 全新的 Swift Testing 入门(二)
  • 用接地气的例子趣谈 WWDC 24 全新的 Swift Testing 入门(三)

想要系统学习 Swift 的小伙伴们,欢迎到我的《Swift语言开发精讲》专栏来逛一逛哦:

在这里插入图片描述

  • 《Swift语言开发精讲》

总结

在本篇博文中,我们进一步讨论了 WWDC24(Xcode 16)中全新 Swift Testing 的驾驭之道,并用多个轻巧的“栗子”让小伙伴们明白晓畅。

感谢观赏,再会啦!????