• iOS开发:你的项目中用到了Traits了吗?
  • 发布于 3天前
  • 87 热度
    0 评论
前言
昨天产品跑过来问:"你们这测试怎么跑了半天还没结束?死机了?"看了眼 Xcode,确实有个测试跑了 15 分钟还在转圈。本来想着手动停掉算了,同事说:"Swift Testing 有超时机制,WWDC 2024 出的 Traits。"

Traits 到底是啥
给测试加标签,但功能远不止标签这么简单。
能做这些事:
1.条件开关测试
2.关联 bug 追踪
3.设置超时时间

4.控制执行顺序


最简单的例子:
@Test(.disabled("这测试太不稳定"))
func someFlakyTest() {
    // 测试代码
}
比注释掉代码优雅多了。

按条件启用/禁用
真机测试推送,模拟器就别折腾了:
struct TestHelper {
    staticvar isSimulator: Bool {
        #if targetEnvironment(simulator)
            returntrue
        #else
            returnfalse
        #endif
    }
}
@Test(.disabled(if: TestHelper.isSimulator, 
                "推送测试只能真机"))
func testPushNotification() {
    // 推送相关测试
}
模拟器自动跳过,不报错不浪费时间。
反过来用 .enabled 也行:
@Test(.enabled(if: ProcessInfo.processInfo.environment["CI"] != nil,
               "CI 环境才跑"))
func testCIFeature() {
    // 堆代码 duidaima.com
    // CI 专属测试
}
关联 Bug
测试失败直接跳转到 issue,这个功能真心不错:
@Test(
    .disabled("等后端修复接口"),
    .bug("https://github.com/YourProject/issues/42")
)
func testLoginAPI() {
    // 登录接口测试
}
还能加 bug ID 和描述:
@Test(.bug("https://github.com/Project/issues/517", 
           id: 517, 
           "头像上传失败"))
func testAvatarUpload() {
    let result = uploadAvatar(image: testImage)
    #expect(result.isSuccess) // 先写测试重现 bug
}
支持各种 bug 系统,包括 Apple 的:
@Test(.bug(id: "FB12345"))  // Feedback Assistant
func testSystemBug() {
    // 系统级 bug
}
测试报告里这些链接都能点。

设置超时
回到开头的问题,有些测试可能卡住:
@Test(.timeLimit(.minutes(10)))
func testFileUpload() {
    let file = createLargeFile(sizeInMB: 100)
    let result = uploadFile(file)
    #expect(result.isSuccess)
}
注意两点:
1.测试套件的超时会传给子测试
2.参数化测试超时分别计算
@Test(.timeLimit(.seconds(5)),
      arguments: [1, 10, 100, 1000])
func testProcessing(itemCount: Int) {
    // 每个参数都有 5 秒
    processItems(count: itemCount)
}
串行执行
Swift Testing 默认并行,快但有时出问题。比如多个测试操作同一数据库:
@Suite(.serialized)
struct DatabaseTests {
    @Test func createUser() { }
    @Test func deleteUser() { }
    @Test func updateUser() { }
}
加 .serialized 顺序执行,避免冲突。
.不过能并行尽量并行,性能差太多。实在不行考虑:
.每个测试用独立数据
.内存数据库

.Mock 真实数据库


实战技巧
1. 组合多个 Traits
@Test(
    .disabled(if: isProduction, "生产环境不跑"),
    .bug("JIRA-1234", "已知问题"),
    .timeLimit(.seconds(30))
)
func testDangerousOperation() {
    // 危险操作
}
2. 测试分组
虽没直接的分组 trait,变通一下:
// 慢速套件
@Suite(.serialized)
struct SlowTests {
    @Test(.timeLimit(.minutes(5)))
    func testHeavyComputation() { }
}

// 快速套件  
struct FastTests {
    @Test(.timeLimit(.seconds(1)))
    func testQuickValidation() { }
}
3. CI/CD 集成
let isCI = ProcessInfo.processInfo.environment["CI"] != nil
let isPR = ProcessInfo.processInfo.environment["GITHUB_EVENT_NAME"] == "pull_request"

@Test(.disabled(if: !isCI, "只在 CI 跑"))
func testCIOnlyFeature() { }

@Test(.disabled(if: isPR, "PR 不跑集成测试"))
func testIntegration() { }

踩过的坑
别滥用串行:并行快很多,必要时才用
超时要合理:太短误杀,太长没意义
Bug ID 及时更新:修复后记得删除

条件判断要准:错了重要测试可能被跳过


最后
Swift Testing 的 Traits 确实让测试管理变优雅了。以前靠注释、手动跳过、CI 配置才能搞定的,现在几个标注就行。你的项目中用到了 Traits 吗?评论区交流下。
用户评论