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

概述

从 WWDC 24 开始,苹果推出了全新的测试机制:Swift Testing。利用它我们可以大幅度简化之前"老态龙钟"的 XCTest 编码范式,并且使得单元测试更加灵动自由,更符合 Swift 语言的优雅品味。

在这里我们会和大家一起初涉并领略 Swift Testing 的测试之美。

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

  1. 何为 Swift Testing?它和之前的 XCTest 有何不同?
  2. 如何将 Swift Testing 集成到 Xcode 项目中?
  3. 御驾亲征:用鲜活的例子说话

测试为先,质量为王!无测试,不软件!

那还等什么呢?Let's testing!!!;)


1. 何为 Swift Testing?它和之前的 XCTest 有何不同?

Swift 测试(Swift Testing)是今年 WWDC 24 中苹果为 Swift 撸码增加的一项重磅功能,它充分利用去年 WWDC 23 推出的宏(Macro)机制,并借助 Swift 语言的"天赋异禀"迅速成为苹果代码开发中的心膂股肱。

在过去,为了完成项目中的单元测试,我们需要借助 XCTest 测试"套件"的力量,可以看到它诞生于远古的 Xcode 7.2:

使用 XCTest 框架,我们可以这样写单元测试:

swift 复制代码
import XCTest

final class ExampleXCTest: XCTestCase {
  // 构造操作
  override func setUpWithError() throws {

  }
  
  // 析构操作
  override func tearDownWithError() throws {

  }

  func testExample() throws {
    XCTAssertTrue(true, "该测试会永远通过!")
  }
}

从上面代码可以看到,我们需要继承 XCTestCase 类实现所需的测试方法集。其中需要设置好必要的测试构造和析构方法,并且所有的测试方法都必须以 "test" 开头。

使用"年代久远"的 XCTest 进行测试似乎有些繁文缛礼、连篇累牍,况且多如牛毛的 XCTAssertXXX 重载方法的选择也会让秃头码农们目不暇接。而使用 Swift Testing 我们可以大大简化 XCTest 的构造过程。

比如,下面是用 Swift Testing 重写的测试代码:

swift 复制代码
import Testing

@Test func swiftTestingExample() {
    // 构造操作
    #expect(true, "该测试会永远通过!")
    // 析构操作
}

从新测试代码可以看到,它们与 XCTest 有以下几点不同:

  1. 不需要先创建派生自 XCTestCase 的测试类;
  2. 直接写测试逻辑,简单明了、一发入魂;
  3. 测试方法名无需限定于特定前缀,而是用 @Test 宏来修饰;

Swift Testing 除了能够简化测试逻辑以外,我们还可以利用它方便的测试"重复"的条件以及灵活的将多个情景相同的测试"聚合成组"。

2. 如何将 Swift Testing 集成到 Xcode 项目中?

使用 Swift Testing 进行单元测试主要有两种方式。

一种是在创建新项目时,就选择将它加入到 Testing System 中去:

否则,要想将 Swift Testing 加入已存在的 Xcode 项目里,我们不能只通过添加一个包含测试逻辑的 swift 文件来达到目的,那样做的话会让 Xcode "大声抱怨"找不到 Testing 框架

至少在 Xcode 16 中暂时无法这样做。我猜测是因为使用 Swift Testing 进行测试并不仅仅是单纯导入了 Testing 框架,Xcode 还需要修改项目的配置信息来深度集成测试环境。

作为替代,我们必须为项目新增一个 Unit Testing 编译目标(Target),并选择 Swift Testing 作为测试系统:

3. 御驾亲征:用鲜活的例子说话

为了能让小伙伴们更深刻的领悟到 Swift Testing 的"魅力",拒绝冷冰冰的说教,我们决定写一个实际的"栗子"来"融会贯通"。

首先,创建一个 Xcode 项目并按照之前的方法加入 Swift Testing 测试系统。

接着,我们新建数据模型:

swift 复制代码
import Foundation

fileprivate let fakeNames = ["黄飞鸿", "齐天大圣", "黑神话悟空"]

struct Item {
    let name: String
    let age: Int
    let power: Double
    let isImmortal: Bool
    
    static func createTestItems() -> [Item] {
        fakeNames.map {
            Item(
                name: $0,
                age: Int.random(
                    in: 1...100
                ),
                power: Double.random(
                    in: 5...1000
                ),
                isImmortal: Bool.random()
            )
        }
    }
}

struct Model {
    static var shared = Model()
    
    private(set) var items = [Item]()
    
    mutating
    func createItems() {
        items = Item.createTestItems()
    }
    
    mutating
    func deleteAllItems() {
        items.removeAll()
    }
}

在上面的代码中我们创建了 Item 类型,并将其包裹到 Model 数据模型中以备后续使用。

随后,我们编写测试逻辑:

swift 复制代码
import Testing
@testable import SwiftTestDEMO

@Test("测试创建 Itmes")
func createItems() {
    var model = Model.shared
    model.createItems()
    #expect(!model.items.isEmpty, "应该成功创建若干 Items!")
}

在上面的代码中,我们使用 createItems 方法验证了创建 Item 是否真正成功。可以看到:我们的 createItems 方法"一枝独秀",摆脱了所有不必要的桎梏,显得那么无拘无束。

按住 Command(⌘)+ U 快捷键,我们第一个测试必须顺利通过:

在后面的博文中,我们将继续介绍 Switch Testing 中一些重要宏的应用场景,敬请期待吧!

总结

在本篇博文中,我们介绍了 WWDC 24(Xcode 16)新引入的 Swift Testing 测试系统、比较了它和 XCTest 的区别、如何集成到 Xcode 项目中,并用一个鲜活的例子讨论了它的金辉玉洁。

感谢观赏,下篇再会啦!8-)

相关推荐
大熊猫侯佩13 小时前
SwiftUI 6.0(iOS 18)自定义容器值(Container Values)让容器布局渐入佳境(下)
swiftui·swift·apple
大熊猫侯佩16 小时前
用接地气的例子趣谈 WWDC 24 全新的 Swift Testing 入门(二)
单元测试·swift·apple
我现在不喜欢coding16 小时前
swift中的self,Self,Class(struct).Type让你头大了嘛?
ios·swift
不二狗16 小时前
每日算法 -【Swift 算法】查找字符串数组中的最长公共前缀
开发语言·算法·swift
不二狗16 小时前
每日算法 -【Swift 算法】将整数转换为罗马数字
开发语言·算法·swift
InternLM1 天前
论文分类打榜赛Baseline:ms-swift微调InternLM实践
swift·internlm·书生
还是鼠鼠1 天前
单元测试-断言&常见注解
java·开发语言·后端·单元测试·maven
YungFan2 天前
SwiftUI-Markdown渲染
swiftui·swift