简体   繁体   English

Kotlin-multiplatform:如何执行 iOS 单元测试

[英]Kotlin-multiplatform: How to execute iOS unit tests

I'm working on a Kotlin-multiplatform library for Android and iOS.我正在为 Android 和 iOS 开发 Kotlin 多平台库。 I want to write some platform-specific unit test.我想编写一些特定于平台的单元测试。 The tests run as expected for the shared code and Android but not for iOS.共享代码和 Android 的测试按预期运行,但不适用于 iOS。

Below the build.gradle file of the shared code module.在共享代码模块的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

and the structure of the SharedCode module is: SharedCode模块的结构为:

└── src
    ├── commonMain
    │   └── kotlin
    ├── commonTest
    │   └── kotlin
    ├── androidMain
    │   └── kotlin
    ├── androidTest
    │   └── kotlin
    ├── iOSMain
    │   └── kotlin
    └── iOSTest
        └── kotlin

The tests added in the androidTest and commonTest folders do run as expected but the ones added in the iOSTest do not run.androidTestcommonTest文件夹中添加的测试确实按预期运行,但在iOSTest添加的iOSTest没有运行。

However, if I replace the the line fromPreset(iOSTarget, 'iOS') { compilations.main.outputKinds('FRAMEWORK') } for fromPreset(presets.macosX64, 'macos') and update the directory names accordly, the tests in the macosTest folder do run as expected.但是,如果我将fromPreset(iOSTarget, 'iOS') { compilations.main.outputKinds('FRAMEWORK') } fromPreset(presets.macosX64, 'macos')fromPreset(presets.macosX64, 'macos')并相应地更新目录名称,则测试macosTest文件夹确实按预期运行。

Why it is not possible to run iOS test when building iOS frameworks?为什么在构建 iOS 框架时无法运行 iOS 测试? Any idea about what I'm doing wrong or how I can make this works?知道我做错了什么或如何使其有效吗? :) :)

Currently the kotlin-multiplatform plugin supports only running tests for host platforms (eg macOS or Windows).目前kotlin-multiplatform插件仅支持对主机平台(例如 macOS 或 Windows)运行测试。 But you can manually add a task for executing iOS tests on a simualtor:但是你可以手动添加一个在模拟器上执行 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
        }
    }
}

See the full build script here .请在此处查看完整的构建脚本。

As I ran into some issues, I'll post my solution here.当我遇到一些问题时,我会在这里发布我的解决方案。

With Kotlin 1.3.50 and XCode 11 I had to change my command line arguments:使用 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)

The answer from @IlyaMatveev works perfect for me. @IlyaMatveev 的答案对我来说很完美。 But I had to updates two lines using Kotlin Version 1.3.41:但我不得不使用 Kotlin 1.3.41 版更新两行:

dependsOn 'linkTestDebugExecutableIos' is now dependsOn 'linkDebugTestIos' dependsOn 'linkTestDebugExecutableIos'现在是dependsOn 'linkDebugTestIos'

def binary = kotlin.targets.ios.binaries.getExecutable('test', 'DEBUG').outputFile is now def binary = kotlin.targets.ios.binaries.getTest("DEBUG").outputFile def binary = kotlin.targets.ios.binaries.getExecutable('test', 'DEBUG').outputFile现在是def binary = kotlin.targets.ios.binaries.getTest("DEBUG").outputFile

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM