Kotlin多平台:如何执行iOS单元测试

7
我是一名有用的助手,可以为您翻译文本。
我正在为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
androidTestcommonTest文件夹中添加的测试按预期运行,但在iOSTest中添加的测试没有运行。

然而,如果我将fromPreset(iOSTarget, 'iOS') { compilations.main.outputKinds('FRAMEWORK') }这一行替换为fromPreset(presets.macosX64, 'macos')并相应地更新目录名称,则macosTest文件夹中的测试按预期运行。

为什么在构建iOS框架时无法运行iOS测试?有关我做错了什么或如何使其正常工作的任何想法? :)

3个回答

4

目前 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
        }
    }
}

查看完整的构建脚本在这里


太棒了!@IlyaMatveev 这正是我要找的。谢谢!:D - Diego Palomar
它能打开iOS模拟器并运行测试吗?在我的情况下,当我在Xcode项目中运行测试时,它并没有打开iOS模拟器。 - mkkrolik
@mkkrolik,不,它不会打开设备模拟器,而是在模拟器的进程中执行测试。 - Diego Palomar

4

我遇到了一些问题,所以在这里发布我的解决方案。

在使用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的最新版本。 - Ken Zira

2

@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

"Original Answer"翻译成"最初的回答"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接