Kotlin-multiplatform:如何执行 iOS 单元测试
Kotlin-multiplatform: How to execute iOS unit tests
我正在为 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 测试?关于我做错了什么或如何使它起作用的任何想法? :)
目前 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 的回答非常适合我。但是我不得不使用 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
由于我 运行 遇到了一些问题,我将 post 我的解决方案放在这里。
使用 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)
我正在为 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 测试?关于我做错了什么或如何使它起作用的任何想法? :)
目前 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 的回答非常适合我。但是我不得不使用 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
由于我 运行 遇到了一些问题,我将 post 我的解决方案放在这里。
使用 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)