Swift Testing vs XCTest:2026 独立开发者要全量迁移吗?

这篇文章帮助独立开发者判断 Swift Testing 与 XCTest 的迁移边界,而不是简单比较 API。文章按新项目、存量 App、UI 与性能测试、Swift Package 以及远程 CI 分别给出迁移优先级、保留条件和可复现的验收证据。

本地回归测试开始出现失败归属不清、UI 测试无法照搬,CI 结果也难以比较。

最快判断:不建议全量重写。新建的单元测试与直接调用业务代码的集成测试优先采用 Swift Testing;存量 XCTest 按维护频率渐进迁移;UI 自动化、性能测试及部分 Objective-C 异常测试继续保留 XCTest。

最后更新于 2026 年 9 月 2 日,版本与互操作信息核实自 Apple Developer 文档、WWDC26 视频、Xcode 27 Beta Release Notes 及 Swift Testing 官方仓库。

这篇文章适合三类人:维护大量 XCTest、担心一次性迁移破坏回归基线的存量 App 开发者;准备建立新测试体系的新项目开发者;以及需要在远程 Mac、Swift Package Manager 或持续集成环境中固定工具链的维护者。

00先按测试类型划分迁移边界

Swift Testing 与 XCTest 的选择,不应从“哪个框架更新”开始,而应从测试任务开始。Apple 当前给出的边界仍然是:Swift Testing 更适合单元测试和直接调用业务代码的集成测试,XCTest 继续覆盖 UI 自动化与性能测试。(测试框架官方说明)

测试类型 推荐策略 迁移优先级 不应忽略的验收证据
新建单元测试 优先 Swift Testing 相同输入下的结果、错误与边界条件一致
直接调用业务代码的集成测试 优先 Swift Testing,必要时复用旧 Helper 中高 依赖注入、异步流程和失败位置保持可诊断
存量 XCTest 单元测试 按修改频率增量迁移 缺陷仍能触发失败,跳过逻辑不改变
UI 自动化 保留 XCTest 页面驱动、控件定位、截图或交互结果
性能测试 保留 XCTest 测量指标、测试计划配置和运行环境一致
Objective-C 异常测试 继续使用 XCTest,必要时使用 Objective-C 测试 异常是否被正确捕获,而不是误判为进程崩溃

能不能把 XCTest 全部换成 Swift Testing?当前答案是否定的。Swift Testing 的定位是扩大 Swift 代码测试的表达能力,不是让所有界面驱动、性能测量和 Objective-C 异常测试都换成同一种写法;迁移资料也将小步迁移作为更稳妥的路径,而不是一次性修改全部旧测试。(WWDC26 测试迁移视频)

01新项目先建立 Swift Testing 单元测试基线

如果项目刚开始建立测试体系,单元测试不必再从 XCTestCase 继承。Swift Testing 使用 @Test 声明测试,#expect 表达预期,#require 用于失败后应立即终止当前测试的前置条件;这些写法对异步代码、参数化测试和并发执行更自然。(Testing 官方文档)

最小示例如下,项目名、Scheme 和路径均不包含真实业务信息:

import Testing

struct PriceCalculatorTests {
    @Test(arguments: [0, 1, 10])
    func rejectsInvalidQuantity(_ quantity: Int) {
        #expect(quantity >= 0)
    }

    @Test
    func createsOrder() throws {
        let order = try #require(makeOrder())
        #expect(order.isValid)
    }
}

这里真正减少的是维护成本,而不是代码行数本身:

  • 参数化测试可以把同一规则与多组输入绑定,避免手写大量重复测试函数;
  • #expect 能保留表达式中的实际值,失败时比只看到断言文字更容易定位;
  • #require 把“没有这个前置条件就没有继续测试意义”的判断写得更清楚;
  • traits 和 tags 可以把测试按平台、功能、优先级或运行节奏筛选到不同的 Test Plan 中。

但新项目也不应为了“框架统一”删除 XCTest UI Tests Target。新项目可以让业务逻辑使用 Swift Testing,同时保留 XCTest UI Tests Target,界面测试仍由专门的 UI 测试入口执行。(Xcode 添加测试的官方说明)

停止条件:如果某个测试需要启动 App、查找界面控件、执行手势,或需要通过 XCTest 记录性能指标,就不要继续把它改写成 Swift Testing 单元测试。这不是迁移不彻底,而是测试能力与工具选择匹配。

02存量项目按维护频率渐进迁移

存量 XCTest 项目从哪里开始改,关键不在文件数量,而在测试未来还会被修改多少次。一次性重写大量稳定测试,通常会把可验证的业务变化变成难以审查的测试重构。

建议把存量测试分为三组:

  1. 正在修改的测试:如果某个测试正好覆盖新功能、修复缺陷或增加并发逻辑,优先在这次修改中迁移到 Swift Testing。
  2. 共享 Helper 较多的测试:先处理 Helper 中的断言与失败报告,再迁移调用它的测试,避免测试主体已经换了框架,但底层辅助方法仍然让失败信息丢失。
  3. 长期稳定且很少修改的测试:只要当前结果可靠、失败位置清楚,就可以暂时保留 XCTest,不必为了统计迁移比例而重写。

Swift Testing 与 XCTest 可以在同一测试 Bundle 中并行构建和运行,也可以在同一个文件中同时导入两个模块;但单个测试函数不应混用两套框架的生命周期与断言语义。(XCTest 迁移官方文档)

迁移共享 Helper 时,必须特别检查跨框架问题。当前迁移资料提供了 nonelimitedcompletestrict 等互操作模式;模式会影响一个框架中的测试调用另一个框架 API 时,失败究竟被忽略、警告、报告为错误,还是直接触发更严格的失败。具体行为应以当前 Xcode 版本的官方说明为准,不要把 Beta 阶段默认行为当作长期承诺。

迁移完成后,至少保留以下验收记录:

  • 原来会失败的缺陷,在新测试中仍然失败;
  • 原来的跳过、取消与条件启用逻辑没有变成“静默通过”;
  • 失败位置能指向真正的 Helper 调用或测试断言,而不是只显示一个无关的测试入口;
  • 迁移前后的 Test Plan 没有意外排除测试 Target、Suite 或参数化用例。

03UI、性能与 Objective-C 场景继续双轨运行

XCTest 为什么仍然需要保留?原因不是历史包袱,而是它还承担着不同类型的测试能力。

UI 自动化依赖 XCUIAutomation 来启动应用、定位控件并模拟用户操作;性能测试则依赖 XCTest 的测量 API 和测试计划配置;涉及 Objective-C 异常时,Swift 代码无法安全处理这类异常,因此相关测试仍应使用 XCTest,必要时使用 Objective-C 编写测试。

可以按下面的能力矩阵安排双轨:

  • Swift Testing:纯 Swift 单元测试、并发业务逻辑、参数化输入、直接调用服务层或领域层的集成测试;
  • XCTest:App 启动与界面操作、UI 回归流程、性能指标采集、需要既有 XCTest 生命周期的测试;
  • 双轨 Helper:共享数据构造、测试夹具和业务断言,但要检查断言 API 是否能被当前互操作模式正确报告;
  • 待复核项目:依赖特定 Xcode Beta 行为、特殊 Scheme 设置或未稳定的测试入口。

这也解释了为什么“把 UI 测试全部迁移掉”通常会造成回归覆盖下降。单元测试可以验证状态转换,却不能证明真实界面能启动、控件可定位、导航流程可完成;两者验证的是不同层次的问题。

04Swift Package 与 Apple App 项目分开判断

Swift Package、Apple 平台 App 和跨平台 Swift 项目,不能简单套用同一条迁移结论。

Swift Testing 官方仓库说明,它已随受支持的 Swift 工具链提供,并支持 Apple 平台、Linux 与 Windows;这意味着不依赖 Apple SDK、模拟器或 UI 的纯 Swift 测试,有机会在 Windows 或 Linux 上提前运行。(Swift Testing 官方仓库)

但以下测试仍然需要 macOS 与 Apple 工具链:

  • 需要 Xcode Scheme、Test Plan 或 xcodebuild 的 App 测试;
  • 需要 iOS 模拟器或真实 Apple 设备的集成验证;
  • 需要 XCTest UI Tests 的界面自动化;
  • 需要 Apple 平台 SDK、签名环境或 App 构建产物的测试。

swift test 与 Xcode Test Plan 也不能互相替代。Swift Package Manager 入口更适合验证包本身的跨平台逻辑;Xcode Test Plan 则可以控制测试 Target、配置、环境变量、代码覆盖率、模拟位置以及运行筛选。(Xcode 测试组织官方说明)

因此,跨平台项目可采用两层策略:先在非 macOS 环境运行纯 Swift 测试,再在 macOS 上运行 Apple 平台集成、UI 与打包相关测试。前者通过不代表后者一定可用,尤其不能把 swift test 的通过结果推广成 iOS App 全链路验证通过。

05远程 CI 固定入口后再提高互操作强度

两套测试框架在远程 CI 中如何对照结果,第一步不是直接把互操作模式切到最严格,而是固定测试入口,避免工具链、Scheme 和 Test Plan 同时变化。

可按以下 7 步执行:

  1. 锁定 Xcode 与 Swift 工具链:记录当前 Xcode 版本、Swift 版本、目标 SDK 和 macOS 版本。Xcode 27 目前仍应按 Beta 资料评估;其 Beta Release Notes 标明需要 Apple Silicon Mac,并要求 macOS Tahoe 26.4 或更高版本,不能把这些条件当成正式版长期承诺。(Xcode 27 Beta Release Notes)
  2. 固定 Scheme 与 Test Plan:不要只执行默认测试入口。为单元测试、集成测试和 UI 测试建立明确的测试计划,并在命令行显式指定。
  3. 记录迁移前基线:保存测试发现数量、通过与失败项、跳过项、失败路径和 .xcresult 结果包。
  4. 先迁移一小组高频修改测试:优先选择业务逻辑测试,保留原有 UI Tests 与性能测试。
  5. 启用互操作检查:先观察 limitedcomplete 模式暴露出的跨框架问题,处理共享 Helper 后,再考虑更严格的 strict 模式。不要为了“绿色构建”暂时使用 none 并把潜在断言问题隐藏起来。
  6. 重复同一 Test Plan:比较迁移前后的发现数量、失败归属、取消行为、日志和测试结果文件,而不只是比较最终退出码。
  7. 验证断线与重启恢复:远程 Mac 重启或会话中断后,仍应能重新选择同一 Scheme 和 Test Plan,运行 Swift Testing、XCTest 单元测试与 XCTest UI Tests,并留下可打开的结果产物。

使用 xcodebuild 执行测试时会生成 .xcresult 结果包,其中可包含会话结果、代码覆盖率和日志;该文件可以在 Xcode 中打开、分析或交给团队成员复核。(运行测试与解读结果的官方说明)

迁移决策可以直接按以下条件执行:

  • 若是新项目,且测试主要直接调用 Swift 业务代码,则选 Swift Testing;UI Tests Target 继续使用 XCTest。
  • 若是存量项目,且测试正在被频繁修改,则迁移当前修改范围;稳定测试先保留 XCTest。
  • 若测试需要界面驱动或性能测量,则保留 XCTest,不因代码风格统一而改写。
  • 若共享 Helper 同时被两套框架调用,则先验证互操作模式与失败归属,再扩大迁移范围。
  • 若项目依赖 swift test 跨平台运行,则先迁移纯 Swift 测试;Apple 平台集成验证回到 macOS 与 Xcode Test Plan。
  • 若远程 CI 无法保存 .xcresult、无法固定 Scheme 或重启后丢失测试环境,则先修复 CI 可复现性,再推进框架迁移。

Xcode 27 仍处于 Beta 阶段,互操作默认行为、日志表现和部分命令行细节可能在 RC 或正式版阶段调整。发布前应再次核对迁移文档、Testing 文档、Xcode Release Notes 与 App Store Connect Release Notes,特别是互操作默认模式发生变化时,不要直接沿用旧流水线配置。

06给独立开发者的最终验收清单

在提交迁移 PR 或切换远程 CI 前,可以逐项勾选:

  • ✅ 新增单元测试是否默认使用 Swift Testing?
  • ✅ 直接调用业务代码的集成测试是否保留了原有测试语义?
  • ✅ UI 自动化是否仍由 XCTest 与 XCUIAutomation 执行?
  • ✅ 性能测试是否继续使用 XCTest 测量 API?
  • ✅ Objective-C 异常场景是否避免用 Swift 测试错误捕获?
  • ✅ 同一 Test Bundle 中两套框架是否都能被发现并执行?
  • ✅ Test Plan、Scheme、环境变量与运行设备是否已固定?
  • ✅ 迁移前后的失败、跳过和取消结果是否逐项对照?
  • .xcresult 是否能在远程任务结束后保存并下载?
  • ✅ 远程 Mac 重启后是否能重复运行同一套测试入口?

如果本地 Mac 无法长期运行双框架回归,问题通常不只是“缺一台编译机”:磁盘中的 Xcode、模拟器、缓存和结果产物需要持续维护,CI 还要处理登录会话、工具链一致性、远程连接中断与重启恢复。相比临时在 Windows 或 Linux 环境中拼接不完整的 Apple 测试链路,远程 Mac 更适合承担需要 Xcode、Test Plan、模拟器和 .xcresult 归档的持续验证任务。

如果只是偶尔验证一个 Swift Package,继续使用本地环境或跨平台机器更合适;如果需要持续运行 iOS 单元测试、UI Tests 和远程回归,NUKCLOUD 的 Mac 远程租赁方案可以作为按周期使用的测试环境。进一步规划区域时,可根据团队网络位置查看 美国远程 Mac 节点日本远程 Mac 节点,再用真实 Test Plan 验证连接、运行与结果留存是否满足项目要求。