news 2026/9/24 16:54:56

Quick 入门实战:在 Xcode 项目中配置 Swift / Objective-C 单元测试

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Quick 入门实战:在 Xcode 项目中配置 Swift / Objective-C 单元测试
  • 测试
  • 开发工具

【免费下载链接】Quick

The Swift (and Objective-C) testing framework.

项目地址:https://gitcode.com/gh_mirrors/qu/Quick
点击查看免费下载

本篇指南围绕 Quick 测试框架的使用前置环节——在 Xcode 工程中正确搭建测试 Target 与跨语言测试桥接,系统讲解 Swift 与 Objective-C 四种组合(Swift 测 Swift、Swift 测 Objective-C、Objective-C 测 Swift、Objective-C 测 Objective-C)的配置步骤,并补充命令行工具项目测试 Target 的创建流程,以及 Quick 在 XCTest 底层如何被发现的源码级原理。读完本文,你将能在自己的 Xcode 项目中稳定接入 Quick 并让测试 Target 正常访问主 Target 的代码。

本文基于当前仓库 SettingUpYourXcodeProject.md 编写,源码证据来自 Sources 目录与 Quick.xcodeproj/project.pbxproj。在开始之前,建议先阅读 安装 Quick 的三种方式(Git Submodules / CocoaPods / Swift Package Manager),并对照 README 中的 Swift 版本兼容表 选择与你的 Swift 版本匹配的 Quick、Nimble 版本。

前置认知:Xcode 默认的测试 Target 与访问主 Target 代码的前提

除 Command Line Tool(命令行工具)项目类型外,使用 Xcode 7 及以上版本新建项目时,工程中会默认包含一个单元测试 Target。对于命令行工具项目,需要手工创建,具体步骤见下文「为命令行工具项目设置测试 Target」。

要编写单元测试,核心前提是:测试 Target 能够使用主 Target 的代码。Xcode 默认生成的测试 Target 只是一个独立的 bundle,它不会自动获得主模块的内部符号可见性,需要按下面四种语言组合分别配置。

用 Swift 测试 Swift 代码

这是最常见的组合。需要完成两件事:

1. 将主 Target 的 "Defines Module" 设置为 YES

在 Xcode 中操作:

  1. 选中你的项目(Project);
  2. 进入 "Build Settings";
  3. 找到 "Packaging" 分组下的 "Defines Module";
  4. 将其值改为 "Yes"。

注意:如果你的 Build Settings 显示为 "Basic"(基本),可能看不到 "Packaging" 分组,需要先切换为 "All"(全部)再查找。

这一设置的意义在于:它让 Xcode 为你的主 Target 生成一个 module(模块),后续@testable import才能按模块名解析到主 Target 的代码。这也是 Swift 语言层面模块化的基本要求。

2. 在测试文件中使用@testable import导入主模块

在测试代码中,通过@testable import导入你的应用模块名。这会把主模块中所有publicinternal(默认访问级别)符号暴露给测试代码,而private符号仍然不可访问。

// MyAppTests.swift import XCTest @testable import MyModule class MyClassTests: XCTestCase { // ... }

为什么是@testable而不是普通import

普通import只能看到public级别的符号;而单元测试经常需要验证模块内部实现细节(例如内部结构体、内部方法),@testable import正是 Apple 为测试场景提供的访问通道。注意其使用前提就是上文第 1 步的 "Defines Module = YES",两者缺一不可。

结合源码理解:Quick 如何借助 XCTest 发现测试

配置好测试 Target 后,Quick 的 Spec 会被 XCTest 自动发现并执行。其机制可以在仓库源码中看到:

  • QuickSpec.h 的注释说明了完整流程:QuickSpec 是XCTestCase的子类,当 Spec 类首次加载时,+[NSObject initialize]被调用,QuickSpec 重写该方法来执行spec(),从而构建 example group 并把示例注册到Quick.World这个全局注册表;
  • 随后 XCTest 会查询测试方法列表。QuickSpec.m 重写了+[XCTestCase testInvocations],遍历World中为该 Spec 类注册的每个 example,动态为类添加实例方法,并返回对应的NSInvocation。这些 invocation 就是最终被 XCTest 执行的测试,其选择器名称会显示在 Xcode 的测试导航栏中;
  • 在单条测试单独运行时(点击导航栏中的单个测试),XCTest 不会隐式调用defaultTestSuite,因此 QuickSpec.m 还重写了instancesRespondToSelector:,显式触发defaultTestSuite来保证 example 仍会被正确生成;
  • 在 Swift Package Manager 场景下,QuickSpec.swift 通过重写defaultTestSuite钩子,调用QuickConfiguration.configureSubclassesIfNeeded完成全局配置并收集每个 Spec 类的 examples,效果等同于 Linux 上在LinuxMain.swift中显式罗列 Spec 类。

也就是说:只要测试 Target 正确链接了 Quick.framework(或通过 SwiftPM 添加了 Quick 依赖),你的QuickSpec子类就会被 XCTest 运行时自动发现,无需手动注册。

用 Swift 测试 Objective-C 代码

如果你要测试的代码是用 Objective-C 编写的,需要让 Swift 测试文件能"看到"对应的头文件:

  1. 为测试 Target 添加一个桥接头文件(Bridging Header);
  2. 在该桥接头文件中#import你要测试的代码所在的头文件。
// MyAppTests-BridgingHeader.h #import "MyClass.h"

配置完成后,就可以在 Swift 测试文件中直接使用MyClass.h中声明的代码了。

桥接头文件的工程配置

在 Xcode 中,桥接头文件的路径通过 Build Settings 中的SWIFT_OBJC_BRIDGING_HEADER指定。仓库自身的测试工程就是一个真实范例:Quick.xcodeproj/project.pbxproj 中配置了:

SWIFT_OBJC_BRIDGING_HEADER = Tests/QuickTests/QuickTests/Helpers/QuickTestsBridgingHeader.h;

该桥接头文件位于 Tests/QuickTests/QuickTests/Helpers/QuickTestsBridgingHeader.h。Quick 自身同时维护 Swift 与 Objective-C 两套测试(见 Tests/QuickTests/QuickTests/FunctionalTests/ObjC 下的*Tests+ObjC.m文件,例如 ItTests+ObjC.m),正是依靠这个桥接头文件在同一个测试 Target 内打通两种语言。你可以照此模式为自己的测试 Target 添加桥接头文件。

用 Objective-C 测试 Swift 代码

Objective-C 无法直接看到 Swift 符号,需要两个步骤:

  1. @objc属性把你希望测试的 Swift 类与方法暴露给 Objective-C;
  2. 在单元测试中导入模块的 Swift 头文件(即 Xcode 自动生成的<模块名>-Swift.h)。
@import XCTest; #import "MyModule-Swift.h" @interface MyClassTests: XCTestCase // ... @end

这里MyModule-Swift.h是 Xcode 在构建时为主 Target 自动生成的头文件,它汇总了所有被@objc暴露的 Swift 声明。注意:Swift 中仅有@objc标记(且继承自NSObject或符合 ObjC 兼容条件的类型)的符号才会出现在这个头文件中,纯 Swift 泛型、private等声明不会出现。

关于模块名的生成规则,仓库中的 NSBundle+CurrentTestBundle.swift 给出了参考实现:模块名取自 bundle 文件名,并转换为合法的 "C99 extended identifier"(对应实现见 String+C99ExtendedIdentifier.swift)。这解释了为什么-Swift.h前缀要使用符合 C 标识符规则的模块名。

用 Objective-C 测试 Objective-C 代码

这是最简单的组合:直接在测试文件中导入被测代码的头文件即可。

// MyAppTests.m @import XCTest; #import "MyClass.h" @interface MyClassTests: XCTestCase // ... @end

无需@testable(Objective-C 没有访问级别隔离到模块内部符号的机制),也无需桥接头文件(同为 Objective-C,编译单元直接可见头文件声明)。

为命令行工具项目设置测试 Target

命令行工具项目默认不含测试 Target,按以下步骤创建:

  1. 在项目导航(project pane)中为你的工程添加一个 Target;
  2. 选择 "OS X Unit Testing Bundle" 模板;
  3. 编辑主 Target 的 Scheme;
  4. 选择 "Test" 节点,点击 "Info" 标题下方的 "+" 按钮;
  5. 在弹出的列表中选择你的测试 bundle。

完成这 5 步后,命令行工具的主 Target 代码即可通过前文所述方式(Swift 场景需先设置 Defines Module 并配合@testable import)被测试 Target 访问。需要注意的是,命令行工具的测试同样遵循上述四种语言组合的配置规则。

常见误用与已知限制

不要直接把源码文件加入测试 Target

一些开发者倾向于把 Swift 源文件直接拖入测试 Target 来"共享代码"。这不是推荐做法:它会导致难以诊断的隐蔽错误(详见 Quick 仓库 issue #91 的讨论),例如同一类型在编译单元间产生符号重复、初始化顺序异常等问题。正确做法始终是使用@testable import(Swift)或桥接头文件 /-Swift.h(跨语言场景)。

Quick 在 Xcode Test Navigator 中的集成限制

Quick 与 Xcode Test Navigator(测试导航器)的集成存在一些已知局限:

  • Quick 测试在运行过之后才会出现在测试导航器中;
  • 重复运行往往会以不可预期的方式重置测试列表;
  • 无法从源码编辑器左侧的 gutter(行槽)直接运行单个 Quick 测试。

如果你希望 Apple 工程师改进这一体验,可以向 Apple 提交 radar,并标注为 rdar://26152293 的重复(duplicate)问题以提升权重。这一限制是 XCTest 运行时动态注入测试方法(上文testInvocations机制)的固有表现:在运行之前,XCTest 并不知道 Spec 中有哪些 example。

隐私与发布注意

Quick 仅用于测试,不应被打包进提交到 App Store Connect 的二进制中(详见 README 的隐私声明);它依赖私有 API 与 Xcode 集成,若被打包会导致应用被拒审。

非 Apple 平台与 SwiftPM 场景下的补充

以上配置均针对 macOS / iOS / tvOS 上的 Xcode 工程。如果你通过 Swift Package Manager 在 Linux 等非 Apple 平台使用 Quick,测试的入口与 Xcode 场景不同:由于 swift-corelibs-xctest 不支持自动发现 Spec 类,需要在Tests/LinuxMain.swift中创建入口并调用QCKMain(实现见 QuickMain.swift),显式传入QuickSpec子类列表、可选的QuickConfiguration子类列表与额外的XCTestCase列表。在当前仓库的 Tests/LinuxMain.swift 中可以看到实际用法。

而在 Apple 平台上使用 SwiftPM 时,则不需要手写LinuxMain.swift:如 QuickSpec.swift 注释所述,XCTest 的自动发现机制由 Objective-C runtime 驱动,defaultTestSuite钩子即可完成配置与 example 收集。当前仓库 Package.swift 声明的最低平台为 macOS 10.15 / iOS 13 / tvOS 13,可作为你在 Apple 平台使用 SwiftPM 集成时的参考基线。

小结:配置检查清单

场景核心配置测试代码中的关键语句
Swift 测 Swift主 Target 设Defines Module = YES@testable import MyModule
Swift 测 Objective-C测试 Target 配置桥接头文件(SWIFT_OBJC_BRIDGING_HEADER桥接头文件中#import "MyClass.h"
Objective-C 测 Swift被测 Swift 符号加@objc#import "MyModule-Swift.h"
Objective-C 测 Objective-C无额外配置#import "MyClass.h"
命令行工具项目新建 "OS X Unit Testing Bundle" Target,并在主 Target Scheme 的 Test 节点中添加同以上四种组合

按照上述清单完成配置后,即可在测试 Target 中import Quick,参照 QuickExamplesAndGroups.md 编写describe/context/it风格的 BDD 测试,并结合 NimbleAssertions.md 使用expect(...).to断言语法。

  • 测试
  • 开发工具

【免费下载链接】Quick

The Swift (and Objective-C) testing framework.

项目地址:https://gitcode.com/gh_mirrors/qu/Quick
点击查看免费下载
上一篇:3分钟学会Python-for-Android:用Python代码创建Android应用的终极指南
下一篇:3分钟搞定Mac Windows驱动安装:Brigadier让你告别手动下载的烦恼

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 16:51:34

dateparse4cj快速上手教程:5分钟完成安装并解析你的第一个日期字符串

dateparse4cj快速上手教程&#xff1a;5分钟完成安装并解析你的第一个日期字符串 【免费下载链接】dateparse4cj dateparse4cj 是一个基于 cangjie 标准库实现的高性能、功能丰富的日期时间解析库。它能够自动识别并解析多种格式的日期字符串&#xff0c;支持全球各种常见日期格…

作者头像 李华
网站建设 2026/9/24 16:50:03

douyin-downloader:一个命令免费把博主主页整体存到本地

douyin-downloader&#xff1a;一个命令免费把博主主页整体存到本地 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback sup…

作者头像 李华
网站建设 2026/9/24 16:47:07

Qwen-Image-2.1-GGUF量化怎么选?Q4_0到Q8_0画质与体积终极对比清单

Qwen-Image-2.1-GGUF量化怎么选&#xff1f;Q4_0到Q8_0画质与体积终极对比清单 【免费下载链接】Qwen-Image-2.1-GGUF 项目地址: https://ai.gitcode.com/hf_mirrors/abenzerps/Qwen-Image-2.1-GGUF Qwen-Image-2.1-GGUF 是通义千问 Qwen-Image-2.1 文生图模型的 GGUF …

作者头像 李华