Gradle添加koin测试依赖的问题

obe*_*rah 2 gradle kotlin junit5 gradle-kotlin-dsl koin

我是一名初学者gradle,希望在我的 Kotlin 项目中使用koin

但是,我收到以下错误

Execution failed for task ':compileTestKotlin'.
> Error while evaluating property 'filteredArgumentsMap' of task ':compileTestKotlin'
   > Could not resolve all files for configuration ':testCompileClasspath'.
      > Could not resolve org.jetbrains.kotlin:kotlin-test-junit5:1.6.20.
        Required by:
            project : > org.jetbrains.kotlin:kotlin-test:1.6.20
         > Module 'org.jetbrains.kotlin:kotlin-test-junit5' has been rejected:
              Cannot select module with conflict on capability 'org.jetbrains.kotlin:kotlin-test-framework-impl:1.6.20' also provided by [org.jetbrains.kotlin:kotlin-test-junit:1.6.10(junitApi)]
      > Could not resolve org.jetbrains.kotlin:kotlin-test-junit:1.6.10.
        Required by:
            project : > io.insert-koin:koin-test:3.2.0-beta-1 > io.insert-koin:koin-test-jvm:3.2.0-beta-1
         > Module 'org.jetbrains.kotlin:kotlin-test-junit' has been rejected:
              Cannot select module with conflict on capability 'org.jetbrains.kotlin:kotlin-test-framework-impl:1.6.10' also provided by [org.jetbrains.kotlin:kotlin-test-junit5:1.6.20(junit5Api)]```

Run Code Online (Sandbox Code Playgroud)

这是我的gradle.build.kts文件

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

val koinVersion = "3.2.0-beta-1"

plugins {
    kotlin("jvm") version "1.6.20"
    kotlin("plugin.serialization") version "1.6.10"
    application
}

group = "org.example"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2")
    implementation("io.insert-koin:koin-core:$koinVersion")
    testImplementation("io.insert-koin:koin-test:$koinVersion")
    testImplementation("io.insert-koin:koin-test-junit5:$koinVersion")
    testImplementation("com.willowtreeapps.assertk:assertk-jvm:0.25")
    testImplementation(kotlin("test"))
}

tasks.test {
    useJUnitPlatform()
}

tasks.withType<KotlinCompile> {
    kotlinOptions.jvmTarget = "1.8"
}

application {
    mainClass.set("MainKt")
}
Run Code Online (Sandbox Code Playgroud)

aSe*_*emy 5

看起来有3个问题

正如我在评论中提到的,Kotlin JVM 和序列化插件的版本不匹配。这些应该总是相同的!

plugins {
  kotlin("jvm") version "1.6.21"
  kotlin("plugin.serialization") version "1.6.21"
  application
}
Run Code Online (Sandbox Code Playgroud)

然而,正如您发现的那样,它仍然不起作用。有一个更大的错误消息,包含三个错误。

  1. Could not resolve io.insert-koin:koin-test-junit5:3.2.0-beta-1
  2. Could not resolve org.jetbrains.kotlin:kotlin-test-junit5:1.6.21
  3. Could not resolve org.jetbrains.kotlin:kotlin-test-junit:1.6.10

让我们一一分析一下

Java 11 库、Java 8 项目

这是 Gradle 给出的第一次失败的原因:

无法解析 io.insert-koin:koin-test-junit5:3.2.0-beta-1。

未找到 io.insert-koin:koin-test-junit5:3.2.0-beta-1 的匹配变体。消费者被配置为查找与 Java 8 兼容的库的 API,最好是类文件的形式,最好针对标准 JVM 进行优化,及其在外部声明的依赖项,以及属性“org.jetbrains.kotlin.platform.type” ' 值为 'jvm' 但是

  • 不兼容,因为该组件声明了一个与Java 11兼容的组件,而使用者需要一个与Java 8兼容的组件

组件koin-test-junit5仅与 Java 11 兼容,但您的项目需要 Java 8 ( kotlinOptions.jvmTarget = "1.8")。

让我们首先使用 Gradle Toolchain解决这个问题

tasks.withType<KotlinCompile>().configureEach {
  kotlinOptions.jvmTarget = "11"
}

kotlin {
  jvmToolchain {
    (this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(11))
  }
}
Run Code Online (Sandbox Code Playgroud)

这解决了 Java 版本不匹配的问题,并留下了另外两个错误。

功能冲突 - 不兼容的库

无法选择功能冲突的模块

无法选择与 [org.jetbrains.kotlin:kotlin-test-junit:1.6.10(junitApi)] 提供的功能“org.jetbrains.kotlin:kotlin-test-framework-impl:1.6.10”有冲突的模块

无法选择与 [org.jetbrains.kotlin:kotlin-test-junit5:1.6.10(junit5Api)] 提供的功能“org.jetbrains.kotlin:kotlin-test-framework-impl:1.6.10”有冲突的模块

理解这一点需要对 Gradle 如何选择版本有相当多的了解。

tl;dr:org.jetbrains.kotlin:kotlin-test-junitorg.jetbrains.kotlin:kotlin-test-junit5是不兼容的。您只能使用其中之一 - 不能同时使用

我真的不明白 Koin 需要什么才能最好地工作。看起来它对 JUnit5 有硬依赖,所以你必须使用这些依赖项,并且无法使用kotlin("test")

dependencies {
  implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2")
  implementation("io.insert-koin:koin-core:$koinVersion")
  testImplementation("io.insert-koin:koin-test:$koinVersion")
  testImplementation("io.insert-koin:koin-test-junit5:$koinVersion")
  testImplementation("com.willowtreeapps.assertk:assertk:0.25")
  testImplementation("org.junit.jupiter:junit-jupiter:5.8.2")


// incompatible with JUnit 5, which I think is required by Koin?
// testImplementation(kotlin("test")) 
}
Run Code Online (Sandbox Code Playgroud)

解释

简而言之,当你使用 Gradle 构建库时,你可以声明'attributes'。它们是自由格式的字符串,因此它们可以是任何东西。他们描述了诸如“这个库需要 Java 11”或“这是测试覆盖率数据”之类的内容。

某些属性对于 Gradle 解决项目的依赖关系非常重要。您最初遇到的错误是由这样一个属性引起的:'capability'。它描述了库生成的 Maven 坐标。

对于 Maven 坐标,如果它们冲突,那么 Gradle 不知道该怎么做,并抛出错误。由用户来修复它。有很多关于冲突解决的 Gradle 文档,但通常最简单的答案是删除任何冲突的依赖项。

功能的有趣之处在于,因为它只是一个字符串,所以您可以向其中添加任何内容。org.jetbrains.kotlin:kotlin-test-junit5和的作者org.jetbrains.kotlin:kotlin-test-junit所做的就是赋予它们相同的能力

org.jetbrains.kotlin:kotlin-test-framework-impl:1.6.10

如果您搜索该库,您会发现它不存在。那是因为这种能力完全是人为的!作者已经弥补了这一点,特别是让 Gradle 会抛出错误,并由用户来修复它。

这就是解决方法:选择kotlin-test-junitkotlin-test-junit5,因为你不能同时拥有两者。