测试
Skip 只需一条命令,就能在两个平台上构建并运行 Swift 测试,帮助你确认代码在 Apple 平台和 Android 上的行为是否一致。核心命令是 skip test,它同时适用于 Skip Lite(将 Swift 转译为 Kotlin)和 Skip Fuse(将 Swift 原生编译到 Android)模块。
skip test 命令
Section titled “skip test 命令”在包目录中运行:
skip testSkip 会同时在两端运行测试集:一端是主机上的原生环境(通常是 Mac,报告中显示为 Darwin (macOS);也支持 Linux,例如 CI 环境),另一端是 Android,然后并排输出两端的一致性报告:
| Test | Case | Darwin (macOS) | Android (Robolectric) || ---------- | ------------ | -------------- | --------------------- || MathTests | testAdd() | PASS (0.00s) | PASS (0.01s) || MathTests | testDivide() | PASS (0.01s) | PASS (0.02s) || | | 100% | 100% |每个测试都会按平台匹配,并显示结果与运行时间。因此,像“Darwin 通过、Android 失败”这类可移植性问题会非常醒目。
同一条 skip test 命令适用于所有模块模式:
- Skip Lite 模块会把 XCTest 和 Swift Testing 用例转译为 Kotlin/JUnit,并在 JVM 上运行。
- Skip Fuse 模块(包括
mode: native模块)会将测试用例原生编译到 Android 并直接运行,底层仍由同一套 Gradle 测试流程驱动。
在 Xcode 中,可以通过标准的测试操作运行同一批测试(底层会调用 swift test),因此结果会像普通 XCTest 结果一样出现在测试导航器和 CI 中。
Android 测试在哪里运行
Section titled “Android 测试在哪里运行”默认情况下,Android 端使用 Robolectric ↗ 在主机本地运行。Robolectric 会在主机 JVM 上模拟 Android 环境,无需模拟器或真机,所以速度最快,适合作为日常开发的默认选择。Robolectric 提供了许多框架 API(如 Context、SharedPreferences 和资源系统),足以覆盖绝大多数单元测试。
如果需要更高的真实度,设置 ANDROID_SERIAL 后即可在已连接的模拟器或真机上运行:
ANDROID_SERIAL=emulator-5554 skip test此时 Skip 会在真实 Android 运行时中以仪器化测试 ↗的形式运行测试,可使用完整的 Android 框架。它比 Robolectric 慢,但最接近生产环境的实际行为。可用 adb devices 列出设备 ID,也可以在 Xcode scheme 的 Run 操作中设置 ANDROID_SERIAL。

Robolectric 与 Android 很接近,但并不完全相同。尤其要注意:由于代码运行在主机 JVM 上,Robolectric 环境中的 #if os(Android) 为 false。Skip 另外定义了 ROBOLECTRIC 符号,让你能在所有类 Android 环境中走 Android 分支:
#if os(Android) || ROBOLECTRIC// 在真机、模拟器和 Robolectric 下都会执行#endif可以使用哪些测试框架,取决于模块模式:
- Skip Lite 模块同时支持 XCTest 和 Swift Testing,两者都会随其他代码一起转译为 Kotlin/JUnit。
- Skip Fuse 原生模块仅支持 Swift Testing,它们会直接运行原生 Swift Testing 运行时(通过
swt入口),不会执行 XCTest 用例。
如果你的代码已经是(或未来可能成为)原生 Fuse 模块,请使用 Swift Testing 编写测试。
- XCTest — 使用
XCTestCase子类和以test开头的方法;XCTAssert*函数会映射到对应的 Android 断言。(仅 Skip Lite) - Swift Testing — 使用
@Test函数、@Suite类型,以及#expect和#require宏。独立的@Test函数(未嵌套在类型中)会被自动包装。
对 Skip Lite 模块而言,转译后的测试用例与其他 Lite 代码遵循相同规则;一些 Swift Testing 特性(参数化测试、trait 和 tag)尚不支持转译。Skip Fuse 原生模块运行真正的 Swift Testing 运行时,因此不受这些限制。
Android 端的测试由自动生成的驱动器 XCSkipTests.swift 负责。通常你不需要碰它,Skip 构建插件会在构建时自动生成。如果需要自定义(例如更换 Gradle 任务),可以在测试目标中添加自己的实现,插件将优先使用它:
#if os(macOS) // Skip 转译测试仅在 macOS 目标上运行import SkipTest
@available(macOS 13, *)final class XCSkipTests: XCTestCase, XCGradleHarness { public func testSkipModule() async throws { try await runGradleTests() }}#endif这个驱动器负责将 Xcode 和 swift test 连接到 Gradle 流程:运行它时,会将测试转译或编译到 Android,执行测试,再把结果以 XCTest 结果的形式回传。
| Robolectric(默认) | 模拟器 / 真机 | |
|---|---|---|
| 命令 | skip test | ANDROID_SERIAL=… skip test |
| 运行位置 | 主机 JVM | 已连接的 Android 模拟器/真机 |
| Android API | 由 Robolectric 模拟 | 完整可用 |
| 速度 | 最快 | 较慢 |
| 真实度 | 适合单元测试 | 最高 |
Skip Lite 和 Skip Fuse 模块都使用这套流程。日常开发中,Robolectric 能提供最快的反馈循环;需要验证依赖真实 Android 运行时的行为时,再切换到模拟器或真机。
如需参考在 GitHub CI 中使用 Android 模拟器运行 Skip Fuse 测试的项目,请查看 skip-fuse-samples ↗。
非 Skip 包
Section titled “非 Skip 包”对于可同时编译到 iOS 和 Android、但没有 skip.yml 的原生 Swift 包(例如 swiftpackageindex.com ↗ 跟踪 Android 兼容性的数千个第三方包),请参阅移植指南中的测试说明。
Android 设备上 Debug 与 Release 构建的性能往往差异很大。测试真实性能时,务必使用 Release 构建在真机上运行。
使用 skip android test 直接在设备上测试
Section titled “使用 skip android test 直接在设备上测试”skip android test 会交叉编译包的测试目标,并不经过 Gradle,直接在真机或模拟器上运行。它有两种模式:
- 命令行模式(默认)—
skip android test— 把测试目标交叉编译为可执行文件,使用adb push将二进制文件、依赖库和所有.resources目录复制到设备,再通过adb shell运行,就像 Linux 上的命令行程序。由于.resources与二进制文件位于同一层,Bundle.module资源查找可正常工作;但此环境没有 JVM 或 JNI,因此无法使用 Android 框架 API。 - APK 模式 —
skip android test --apk— 把测试打包成真正的 Android 应用(由aapt2、zipalign和apksigner组装),通过adb install安装,并以 Android Activity 的形式运行。这种模式提供完整的 JNI 环境和全部 Android 框架能力,但无法解析从 APK 原生库目录加载的资源。可传入--event-stream-output-path <file>,在本地捕获原始测试事件 JSON。