测试你的跨平台应用 − 教程
在本教程中,你将学习如何在 Kotlin 跨平台应用中创建、配置和运行测试。
跨平台项目的测试可分为两类:
通用代码测试。这些测试可使用任何支持的框架在任何平台上运行。
平台特定代码测试。这些测试对验证平台特定逻辑至关重要,它们使用平台特定框架,并能利用其附加功能(如更丰富的 API 和更广泛的断言)。
跨平台项目同时支持这两类测试。本教程将首先展示如何在简单的 Kotlin 跨平台项目中为通用代码设置、创建和运行单元测试。随后,你将通过一个更复杂的示例,学习如何为通用代码和平台特定代码编写测试。
测试简单跨平台项目
创建项目
准备跨平台开发环境。 检查必要工具列表并按需更新至最新版本。
打开 Kotlin 跨平台向导。
在 New project 选项卡中,确保选中 Android 和 iOS 选项。
对于 iOS,选择 Do not share UI 选项(本教程无需此功能)。
点击 Download 按钮并解压生成的压缩包。

编写代码
启动 Android Studio。
在欢迎界面点击 Open ,或通过编辑器菜单选择 File | Open。
导航至解压的项目文件夹,点击 Open。
Android Studio 会检测到该文件夹包含 Gradle 构建文件,并将其作为新项目打开。
Android Studio 默认视图针对 Android 开发优化。为获得更适合跨平台开发的完整项目文件结构,请将视图从 Android 切换至 Project:
在
shared/src/commonMain/kotlin
目录下创建common.example.search
子目录。在此目录中创建 Kotlin 文件
Grep.kt
,并添加以下函数:fun grep(lines: List<String>, pattern: String, action: (String) -> Unit) { val regex = pattern.toRegex() lines.filter(regex::containsMatchIn) .forEach(action) }该函数模拟 UNIX grep 命令的功能,接收文本行列表、作为正则表达式的模式,以及当行匹配模式时触发的函数。
添加测试
现在测试通用代码。关键部分是为通用测试创建源集,并添加 kotlin.test
API 库作为依赖。
在
shared
目录中打开build.gradle.kts
文件。添加通用测试源集及kotlin.test
依赖:sourceSets { //... commonTest.dependencies { implementation(libs.kotlin.test) } }添加依赖后,系统会提示同步项目。点击 Sync Now 同步 Gradle 文件:
commonTest
源集存储所有通用测试。现在需要在项目中创建同名目录:右键点击
shared/src
目录,选择 New | Directory 。IDE 将显示选项列表。输入
commonTest/kotlin
路径筛选选项,然后从列表中选择:
在
commonTest/kotlin
目录中创建common.example.search
包。在此包中创建
Grep.kt
文件并添加以下单元测试:import kotlin.test.Test import kotlin.test.assertContains import kotlin.test.assertEquals class GrepTest { companion object { val sampleData = listOf( "123 abc", "abc 123", "123 ABC", "ABC 123" ) } @Test fun shouldFindMatches() { val results = mutableListOf<String>() grep(sampleData, "[a-z]+") { results.add(it) } assertEquals(2, results.size) for (result in results) { assertContains(result, "abc") } } }
可以看到,导入的注解和断言既不依赖平台也不依赖框架。运行测试时,平台特定框架将提供测试运行器。
探索 kotlin.test
API
kotlin.test
库提供与平台无关的注解和断言。 Test
等注解会映射到所选框架提供的注解或其最接近的等效项。
断言通过 Asserter
接口的实现执行。该接口定义了测试中常用的各种检查操作。API 提供默认实现,但通常你会使用框架特定的实现。
例如,JVM 支持 JUnit 4、JUnit 5 和 TestNG 框架。在 Android 上, assertEquals()
调用可能由 JUnit4Asserter
实例执行。在 iOS 上, Asserter
类型的默认实现与 Kotlin/Native 测试运行器配合使用。
运行测试
可通过以下方式执行测试:
使用行号旁的 Run 图标运行
shouldFindMatches()
测试函数。通过右键菜单运行整个测试文件。
使用类旁的 Run 图标运行
GrepTest
测试类。
还可使用快捷键 ⌃ ⇧ F10/Ctrl+Shift+F10 。无论选择哪种方式,都会显示可运行测试的目标平台列表:

对于 android
选项,测试使用 JUnit 4 运行。对于 iosSimulatorArm64
,Kotlin 编译器检测测试注解并创建由 Kotlin/Native 测试运行器执行的 测试二进制文件。
以下是测试成功运行的输出示例:

处理更复杂的项目
为通用代码编写测试
你已为 grep()
函数创建了通用代码测试。现在来看更高级的通用代码测试示例 ——CurrentRuntime
类。该类包含代码运行平台的信息,例如 Android 单元测试在本地 JVM 运行时可能显示 "OpenJDK" 和 "17.0"。
CurrentRuntime
实例应通过平台名称(字符串)和可选版本号创建。当存在版本号时,只需提取字符串开头的数字部分(如果存在)。
在
commonMain/kotlin
目录中创建org.kmp.testing
子目录。在此目录中创建
CurrentRuntime.kt
文件并添加以下实现:class CurrentRuntime(val name: String, rawVersion: String?) { companion object { val versionRegex = Regex("^[0-9]+(\\.[0-9]+)?") } val version = parseVersion(rawVersion) override fun toString() = "$name version $version" private fun parseVersion(rawVersion: String?): String { val result = rawVersion?.let { versionRegex.find(it) } return result?.value ?: "unknown" } }在
commonTest/kotlin
目录中创建org.kmp.testing
包。在此包中创建
CurrentRuntimeTest.kt
文件并添加以下平台和框架无关的测试:import kotlin.test.Test import kotlin.test.assertEquals class CurrentRuntimeTest { @Test fun shouldDisplayDetails() { val runtime = CurrentRuntime("MyRuntime", "1.1") assertEquals("MyRuntime version 1.1", runtime.toString()) } @Test fun shouldHandleNullVersion() { val runtime = CurrentRuntime("MyRuntime", null) assertEquals("MyRuntime version unknown", runtime.toString()) } @Test fun shouldParseNumberFromVersionString() { val runtime = CurrentRuntime("MyRuntime", "1.2 Alpha Experimental") assertEquals("MyRuntime version 1.2", runtime.toString()) } @Test fun shouldHandleMissingVersion() { val runtime = CurrentRuntime("MyRuntime", "Alpha Experimental") assertEquals("MyRuntime version unknown", runtime.toString()) } }
可通过 IDE 提供的任意方式 运行此测试。
添加平台特定测试
现在你已掌握通用代码测试的编写,接下来为 Android 和 iOS 编写平台特定测试。
为创建 CurrentRuntime
实例,在通用的 CurrentRuntime.kt
文件中声明以下函数:
该函数需在每个支持的平台上分别实现,否则构建将失败。除了在各平台实现此函数外,还需提供测试。下面为 Android 和 iOS 创建测试。
Android 测试
在
androidMain/kotlin
目录中创建org.kmp.testing
包。在此包中创建
AndroidRuntime.kt
文件,并实现预期的determineCurrentRuntime()
函数:actual fun determineCurrentRuntime(): CurrentRuntime { val name = System.getProperty("java.vm.name") ?: "Android" val version = System.getProperty("java.version") return CurrentRuntime(name, version) }在
shared/src
目录中创建测试目录:右键点击
shared/src
目录,选择 New | Directory。输入
androidUnitTest/kotlin
路径筛选选项,然后从列表中选择:
在
kotlin
目录中创建org.kmp.testing
包。在此包中创建
AndroidRuntimeTest.kt
文件并添加以下 Android 测试:import kotlin.test.Test import kotlin.test.assertContains import kotlin.test.assertEquals class AndroidRuntimeTest { @Test fun shouldDetectAndroid() { val runtime = determineCurrentRuntime() assertContains(runtime.name, "OpenJDK") assertEquals(runtime.version, "17.0") } }
Android 特定测试在本地 JVM 上运行可能看似奇怪。这是因为这些测试作为本地单元测试在当前机器上运行。如 Android Studio 文档 所述,这些测试与在设备或模拟器上运行的插桩测试不同。
你可以在项目中添加其他类型的测试。关于插桩测试,请参阅 Touchlab 指南。
iOS 测试
在
iosMain/kotlin
目录中创建org.kmp.testing
子目录。在此目录中创建
IOSRuntime.kt
文件,并实现预期的determineCurrentRuntime()
函数:import kotlin.experimental.ExperimentalNativeApi import kotlin.native.Platform @OptIn(ExperimentalNativeApi::class) actual fun determineCurrentRuntime(): CurrentRuntime { val name = Platform.osFamily.name.lowercase() return CurrentRuntime(name, null) }在
shared/src
目录中创建新目录:右键点击
shared/src
目录,选择 New | Directory。输入
iosTest/kotlin
路径筛选选项,然后从列表中选择:
在
iosTest/kotlin
目录中创建org.kmp.testing
子目录。在此目录中创建
IOSRuntimeTest.kt
文件并添加以下 iOS 测试:package org.kmp.testing import kotlin.test.Test import kotlin.test.assertEquals class IOSRuntimeTest { @Test fun shouldDetectOS() { val runtime = determineCurrentRuntime() assertEquals(runtime.name, "ios") assertEquals(runtime.version, "unknown") } }
运行多个测试并分析报告
此时,你已拥有通用、Android 和 iOS 的实现代码及其测试。项目目录结构应类似如下:

可通过右键菜单或快捷键运行单个测试。另一种方式是使用 Gradle 任务。例如,运行 allTests
Gradle 任务会使用相应的测试运行器执行项目中所有测试:

运行测试时,除了 IDE 中的输出外,还会生成 HTML 报告。你可以在 shared/build/reports/tests
目录中找到它们:

运行 allTests
任务并检查生成的报告:
allTests/index.html
文件包含通用测试和 iOS 测试的合并报告(iOS 测试依赖通用测试,在其之后运行)。testDebugUnitTest
和testReleaseUnitTest
文件夹包含两种默认 Android 构建变体的报告(目前 Android 测试报告不会自动合并到allTests
报告中)。

跨平台项目测试使用规则
你已学会在 Kotlin 跨平台应用中创建、配置和执行测试。在未来的项目中,请记住:
编写通用代码测试时,仅使用 kotlin.test 等多平台库。将依赖添加到
commonTest
源集。kotlin.test
API 中的Asserter
类型应仅间接使用。虽然Asserter
实例可见,但测试中无需直接调用。始终遵循测试库 API。编译器与 IDE 会阻止你使用框架特定功能。
虽然
commonTest
中使用的测试框架不影响结果,但建议用每个计划使用的框架运行测试,以验证开发环境配置正确。编写平台特定代码测试时,可使用对应框架的功能(如注解和扩展)。
可通过 IDE 或 Gradle 任务运行测试。
运行测试时会自动生成 HTML 测试报告。