Kotlin-multiplatform:如何执行 iOS 单元测试
Posted
技术标签:
【中文标题】Kotlin-multiplatform:如何执行 iOS 单元测试【英文标题】:Kotlin-multiplatform: How to execute iOS unit tests 【发布时间】:2019-05-29 02:42:06 【问题描述】:我正在开发适用于 android 和 ios 的 Kotlin 多平台库。我想编写一些特定于平台的单元测试。测试在共享代码和 Android 上按预期运行,但在 iOS 上不正常。
在共享代码模块的build.gradle
文件下方。
apply plugin: "kotlin-multiplatform"
kotlin
targets
final def iOSTarget = System.getenv('SDK_NAME')?.startsWith("iphoneos") \
? presets.iosArm64 : presets.iosX64
fromPreset(iOSTarget, 'iOS')
compilations.main.outputKinds('FRAMEWORK')
fromPreset(presets.jvm, 'android')
sourceSets
commonMain.dependencies
implementation "org.jetbrains.kotlin:kotlin-stdlib-common"
commonTest.dependencies
implementation 'org.jetbrains.kotlin:kotlin-test'
implementation 'org.jetbrains.kotlin:kotlin-test-junit'
androidMain.dependencies
implementation "org.jetbrains.kotlin:kotlin-stdlib"
androidTest
dependencies
implementation 'org.jetbrains.kotlin:kotlin-test'
implementation 'org.jetbrains.kotlin:kotlin-test-junit'
iOSMain.dependencies
iOSTest.dependencies
implementation 'org.jetbrains.kotlin:kotlin-test'
implementation 'org.jetbrains.kotlin:kotlin-test-junit'
// workaround for https://youtrack.jetbrains.com/issue/KT-27170
configurations
compileClasspath
task packForXCode(type: Sync)
final File frameworkDir = new File(buildDir, "xcode-frameworks")
final String mode = project.findProperty("XCODE_CONFIGURATION")?.toUpperCase() ?: 'DEBUG'
inputs.property "mode", mode
dependsOn kotlin.targets.iOS.compilations.main.linkTaskName("FRAMEWORK", mode)
from kotlin.targets.iOS.compilations.main.getBinary("FRAMEWORK", mode).parentFile
into frameworkDir
doLast
new File(frameworkDir, 'gradlew').with
text = "#!/bin/bash\nexport 'JAVA_HOME=$System.getProperty("java.home")'\ncd '$rootProject.rootDir'\n./gradlew \$@\n"
setExecutable(true)
tasks.build.dependsOn packForXCode
而SharedCode
模块的结构是:
└── src
├── commonMain
│ └── kotlin
├── commonTest
│ └── kotlin
├── androidMain
│ └── kotlin
├── androidTest
│ └── kotlin
├── iOSMain
│ └── kotlin
└── iOSTest
└── kotlin
androidTest
和 commonTest
文件夹中添加的测试确实按预期运行,但 iOSTest
中添加的测试没有运行。
但是,如果我将 fromPreset(iOSTarget, 'iOS') compilations.main.outputKinds('FRAMEWORK')
行替换为 fromPreset(presets.macosX64, 'macos')
并相应地更新目录名称,macosTest
文件夹中的测试会按预期运行。
为什么在构建 iOS 框架时无法运行 iOS 测试?关于我做错了什么或如何使它起作用的任何想法? :)
【问题讨论】:
【参考方案1】:目前kotlin-multiplatform
插件仅支持在主机平台(例如 macOS 或 Windows)上运行测试。但是你可以手动添加一个任务来在模拟器上执行 iOS 测试:
task iosTest
def device = project.findProperty("iosDevice")?.toString() ?: "iPhone 8"
dependsOn 'linkTestDebugExecutableIos'
group = JavaBasePlugin.VERIFICATION_GROUP
description = "Runs tests for target 'ios' on an iOS simulator"
doLast
def binary = kotlin.targets.ios.binaries.getExecutable('test', 'DEBUG').outputFile
exec
commandLine 'xcrun', 'simctl', 'spawn', device, binary.absolutePath
查看完整的构建脚本here。
【讨论】:
太棒了,@IlyaMatveev 这就是我想要的。谢谢! :D 它会打开 ios 模拟器并运行测试吗?在我的情况下,它不会像我在 xcode 项目中运行测试时那样打开 ios 模拟器。 @mkkrolik,不,它不会打开设备模拟器,而是在模拟器的进程中执行测试。【参考方案2】:当我遇到一些问题时,我会在这里发布我的解决方案。
使用 Kotlin 1.3.50
和 XCode 11
我不得不更改我的命令行参数:
val iosTest: Task by tasks.creating
val device = project.findProperty("iosDevice")?.toString() ?: "iPhone 8"
val testExecutable = kotlin.targets.getByName<KotlinNativeTarget>("iosX64").binaries.getTest("DEBUG")
dependsOn(testExecutable.linkTaskName)
group = JavaBasePlugin.VERIFICATION_GROUP
description = "Runs tests for target 'ios' on an iOS simulator"
doLast
exec
println(testExecutable.outputFile.absolutePath)
commandLine( "xcrun", "simctl", "spawn", "--standalone", device, testExecutable.outputFile.absolutePath)
tasks.getByName("allTests").dependsOn(iosTest)
【讨论】:
这应该被标记为最新版本的 kotlin 和 xcode 的答案【参考方案3】:@IlyaMatveev 的回答非常适合我。但我不得不使用 Kotlin 版本 1.3.41 更新两行:
dependsOn 'linkTestDebugExecutableIos'
就是现在
dependsOn 'linkDebugTestIos'
def binary = kotlin.targets.ios.binaries.getExecutable('test', 'DEBUG').outputFile
现在是def binary = kotlin.targets.ios.binaries.getTest("DEBUG").outputFile
【讨论】:
以上是关于Kotlin-multiplatform:如何执行 iOS 单元测试的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Kotlin-Multiplatform 在 iOS 应用程序的后台线程中运行任务?
Kotlin-Multiplatform 中的 CPointer
在 kotlin-multiplatform 上生成 UUID?