我开始使用Kotest在Kotlin中进行单元测试。我使用以下以某种方式与Kotest集成的技术:

  • Kotest本身
  • Kotlin / JVM
  • Gradle
  • 魅力
  • Pitest
  • IntelliJ IDEA插件“Kotest”

  • 在gradle中,我包括以下依赖项:
  • io.kotest:kotest-runner-junit5:$kotest_version:Kotest框架
  • io.kotest:kotest-assertions-core:$kotest_version:Kotest核心JVM断言
  • io.kotest:kotest-property:$kotest_version:Kotest属性测试
  • io.kotest:kotest-extensions-allure:$kotest_version:魅力
  • 的数据收集
  • io.kotest:kotest-plugins-pitest:$kotest_version:Pitest插件

  • 现在的问题是,当我通过gradle :test任务运行测试时,出现以下异常:java.lang.IllegalArgumentException: Received a failure event for test with unknown id '2.27'. Registered test ids: '[2.1, :test, 2.25]'未知ID /已注册ID在每次测试运行中都不同。实际上出现了很多错误,但是那是最后一个出现的错误。以下是完整的gradle输出(缩短了内部调用):
    Testing started at 18:39 ...
    
    > Task :kaptGenerateStubsKotlin UP-TO-DATE
    > Task :kaptKotlin UP-TO-DATE
    > Task :compileKotlin UP-TO-DATE
    > Task :compileJava NO-SOURCE
    > Task :processResources UP-TO-DATE
    > Task :classes UP-TO-DATE
    > Task :kaptGenerateStubsTestKotlin UP-TO-DATE
    > Task :kaptTestKotlin UP-TO-DATE
    > Task :compileTestKotlin UP-TO-DATE
    > Task :preTest
    > Task :compileTestJava NO-SOURCE
    > Task :processTestResources UP-TO-DATE
    > Task :testClasses UP-TO-DATE
    > Task :test
    ~~~ Kotest Configuration ~~~
    -> Parallelization factor: 1
    -> Default test timeout: 600000ms
    -> Default test order: Sequential
    -> Default isolation mode: SingleInstance
    -> Global soft assertations: False
    -> Write spec failure file: False
    -> Fail on ignored tests: False
    -> Spec execution order: SpecExecutionOrder
    -> Extensions
      - io.kotest.engine.extensions.SystemPropertyTagExtension
      - io.kotest.core.extensions.RuntimeTagExtension
      - io.kotest.engine.extensions.RuntimeTagExpressionExtension
    -> Listeners
      - io.kotest.extensions.allure.AllureTestReporter
      - class io.kotest.engine.config.LoadConfigFromClasspathKt$toDetectedConfig$beforeAfterAllListener$1
    
    Nov. 04, 2020 6:39:48 NACHM. org.junit.platform.launcher.core.TestExecutionListenerRegistry lambda$notifyEach$1
    WARNING: TestExecutionListener [org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestExecutionListener] threw exception for method: executionFinished(TestIdentifier [uniqueId = '[engine:kotest]/[spec:com.example.core.common.JSONFileTests]/[test:Writing to and reading from file should result in the original value]', parentId = '[engine:kotest]/[spec:com.example.core.common.JSONFileTests]', displayName = 'Writing to and reading from file should result in the original value', legacyReportingName = 'Writing to and reading from file should result in the original value', source = FileSource [file = D:\dev\Minecraft Server Watcher\msw-server\JSONFileTests.kt, filePosition = FilePosition [line = 40, column = -1]], tags = [], type = TEST], TestExecutionResult [status = FAILED, throwable = java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: OffsetSeconds])
    java.lang.AssertionError <3 internal calls>
        at jdk.internal.reflect.GeneratedMethodAccessor29.invoke(Unknown Source) <11 internal calls>
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) <17 internal calls>
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
        at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:274)
        at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:84)
        at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
        at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
        at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
        at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source) <5 internal calls>
    
    Nov. 04, 2020 6:39:48 NACHM. org.junit.platform.launcher.core.TestExecutionListenerRegistry lambda$notifyEach$1
    WARNING: TestExecutionListener [org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestExecutionListener] threw exception for method: executionFinished(TestIdentifier [uniqueId = '[engine:kotest]/[spec:com.example.core.common.JSONFileTests]/[test:Writing to and reading from file should result in the original value]', parentId = '[engine:kotest]/[spec:com.example.core.common.JSONFileTests]', displayName = 'Writing to and reading from file should result in the original value', legacyReportingName = 'Writing to and reading from file should result in the original value', source = FileSource [file = D:\dev\Minecraft Server Watcher\msw-server\JSONFileTests.kt, filePosition = FilePosition [line = 40, column = -1]], tags = [], type = TEST], TestExecutionResult [status = FAILED, throwable = java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: OffsetSeconds])
    java.lang.AssertionError <3 internal calls>
        at jdk.internal.reflect.GeneratedMethodAccessor29.invoke(Unknown Source) <11 internal calls>
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) <17 internal calls>
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
        at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:274)
        at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:84)
        at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
        at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
        at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
        at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source) <5 internal calls>
        at java.base/java.lang.Thread.run(Thread.java:834)
    
    Nov. 04, 2020 6:39:48 NACHM. org.junit.platform.launcher.core.TestExecutionListenerRegistry lambda$notifyEach$1
    WARNING: TestExecutionListener [org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestExecutionListener] threw exception for method: executionFinished(TestIdentifier [uniqueId = '[engine:kotest]/[spec:com.example.core.common.JSONFileTests]/[test:Writing to and reading from file should result in the original value]', parentId = '[engine:kotest]/[spec:com.example.core.common.JSONFileTests]', displayName = 'Writing to and reading from file should result in the original value', legacyReportingName = 'Writing to and reading from file should result in the original value', source = FileSource [file = D:\dev\Minecraft Server Watcher\msw-server\JSONFileTests.kt, filePosition = FilePosition [line = 40, column = -1]], tags = [], type = TEST], TestExecutionResult [status = SUCCESSFUL, throwable = null])
    java.lang.AssertionError <3 internal calls>
        at jdk.internal.reflect.GeneratedMethodAccessor29.invoke(Unknown Source) <11 internal calls>
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) <17 internal calls>
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
        at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:274)
        at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:84)
        at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
        at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
        at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
        at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source) <5 internal calls>
        at java.base/java.lang.Thread.run(Thread.java:834)
    
    Nov. 04, 2020 6:39:48 NACHM. org.junit.platform.launcher.core.TestExecutionListenerRegistry lambda$notifyEach$1
    WARNING: TestExecutionListener [org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestExecutionListener] threw exception for method: executionFinished(TestIdentifier [uniqueId = '[engine:kotest]/[spec:com.example.core.common.JSONFileTests]/[test:Writing to and reading from file should result in the original value]', parentId = '[engine:kotest]/[spec:com.example.core.common.JSONFileTests]', displayName = 'Writing to and reading from file should result in the original value', legacyReportingName = 'Writing to and reading from file should result in the original value', source = FileSource [file = D:\dev\Minecraft Server Watcher\msw-server\JSONFileTests.kt, filePosition = FilePosition [line = 40, column = -1]], tags = [], type = TEST], TestExecutionResult [status = SUCCESSFUL, throwable = null])
    java.lang.AssertionError <3 internal calls>
        at jdk.internal.reflect.GeneratedMethodAccessor29.invoke(Unknown Source) <11 internal calls>
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) <17 internal calls>
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
        at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:274)
        at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:84)
        at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
        at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
        at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
        at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source) <5 internal calls>
        at java.base/java.lang.Thread.run(Thread.java:834)
    
    Nov. 04, 2020 6:39:48 NACHM. org.junit.platform.launcher.core.TestExecutionListenerRegistry lambda$notifyEach$1
    WARNING: TestExecutionListener [org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestExecutionListener] threw exception for method: executionFinished(TestIdentifier [uniqueId = '[engine:kotest]/[spec:com.example.core.common.JSONFileTests]/[test:Writing to and reading from file should result in the original value]', parentId = '[engine:kotest]/[spec:com.example.core.common.JSONFileTests]', displayName = 'Writing to and reading from file should result in the original value', legacyReportingName = 'Writing to and reading from file should result in the original value', source = FileSource [file = D:\dev\Minecraft Server Watcher\msw-server\JSONFileTests.kt, filePosition = FilePosition [line = 40, column = -1]], tags = [], type = TEST], TestExecutionResult [status = SUCCESSFUL, throwable = null])
    java.lang.AssertionError <3 internal calls>
        at jdk.internal.reflect.GeneratedMethodAccessor29.invoke(Unknown Source) <11 internal calls>
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) <17 internal calls>
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
        at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:274)
        at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:84)
        at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
        at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
        at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
        at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source) <5 internal calls>
        at java.base/java.lang.Thread.run(Thread.java:834)
    
    Received a failure event for test with unknown id '2.27'. Registered test ids: '[2.1, :test, 2.25]'
    java.lang.IllegalArgumentException: Received a failure event for test with unknown id '2.27'. Registered test ids: '[2.1, :test, 2.25]' <19 internal calls>
        at java.base/java.lang.Thread.run(Thread.java:834)
    > Task :test FAILED
    FAILURE: Build failed with an exception.
    * What went wrong:
    Execution failed for task ':test'.
    > Received a failure event for test with unknown id '2.27'. Registered test ids: '[2.1, :test, 2.25]'
    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
    * Get more help at https://help.gradle.org
    BUILD FAILED in 5s
    10 actionable tasks: 2 executed, 8 up-to-date
    
    可能相关的内容:
    1.我在build.gradle.kts中使用自定义任务配置
    我的build.gradle.kts文件的以下部分涵盖了所有与测试相关的内容,包括一个设置测试环境的任务,以及随后要清理的第二个任务:
    tasks.withType<Test> {
        useJUnitPlatform()
    }
    
    allure {
        autoconfigure = false
        version = "2.13.6"
    }
    
    configure<PitestPluginExtension> {
        testPlugin.set("Kotest")
        targetClasses.set(listOf("com.example.*"))
    }
    
    val testDir1Path = "/src/test/resources/DirectoryTest"
    val testDir2Path = "/src/test/resources/Create"
    tasks.register("preTest") {
        doLast {
            mkdir(testDir1Path)
            file("$testDir1Path/json00.json").apply { createNewFile() }.writeText("{ \"s\": \"s\", \"i\": 0, \"b\": true}")
            file("$testDir1Path/json01.json").apply { createNewFile() }.writeText("{}")
            file("$testDir1Path/json02.json").apply { createNewFile() }.writeText("{}")
            file("$testDir1Path/json03.json").apply { createNewFile() }.writeText("{}")
            file("$testDir1Path/json04.json").apply { createNewFile() }.writeText("{}")
            file("$testDir1Path/json05.json").apply { createNewFile() }.writeText("{}")
            file("$testDir1Path/json06.json").apply { createNewFile() }.writeText("{}")
        }
    }
    
    tasks.register<Delete>("postTest") {
        for (task in tasks.withType<Test>()) {
            mustRunAfter(task)
        }
        delete(testDir1Path)
        delete(testDir2Path)
        delete("/src/test/resources/NonExistent") // might be created by :pitest
    }
    
    tasks.withType<Test>().configureEach {
        dependsOn("preTest")
    }
    
    2.首先导致错误的测试套件
    当我在下面的Kotest测试类中工作时,发生了错误,更准确地说,是在我尝试实现Test Factory并将其包括在内之后发生的错误:
    class JSONFileTests : FunSpec({
        test("Loading a file into the model JSONModel01 should work") {
            shouldNotThrowAny {
                JSONFile("$exists/json00.json", JSONModel01.serializer())
            }.get() shouldBe JSONModel01("s", 0, true)
        }
    
        include("JSONModel01: ", echoTests(m1))
        include("JSONModel02: ", echoTests(m2))
        include("JSONModel03: ", echoTests(m3))
        include("JSONModel04: ", echoTests(m4))
        include("JSONModel05: ", echoTests(m5))
        include("JSONModel06: ", echoTests(m6))
    }) {
        companion object {
            private val m1 = JSONFile("$exists/json01.json", JSONModel01.serializer()) to JSONModel01()
            private val m2 = JSONFile("$exists/json02.json", JSONModel02.serializer()) to JSONModel02()
            private val m3 = JSONFile("$exists/json03.json", JSONModel03.serializer()) to JSONModel03()
            private val m4 = JSONFile("$exists/json04.json", JSONModel04.serializer()) to JSONModel04()
            private val m5 = JSONFile("$exists/json05.json", JSONModel05.serializer()) to JSONModel05()
            private val m6 = JSONFile("$exists/json06.json", JSONModel06.serializer()) to JSONModel06()
    
            private fun cleanupAll() {
                m1.first.reload()
                m2.first.reload()
                m3.first.reload()
                m4.first.reload()
                m5.first.reload()
                m6.first.reload()
            }
    
            private fun <T : JSONModelMarker> echoTests(model: Pair<JSONFile<T>, T>) = funSpec {
                test("Writing to and reading from file should result in the original value") {
                    model.first.apply { setAndCommit(model.second) }.get() shouldBe model.second
                    model.first.reload()
                }
            }
        }
    }
    
    所有JSONModelXX类都是仅用于测试的模型数据类。 JSONModelMarker是由所有JSONModelXX类实现的标记接口(interface)。 JSONFile<T>是我要测试的类。
    3. IntelliJ通知
    我总是从IntelliJ收到“所有测试成功”的通知,但是当我查看测试工具窗口时,由于gradle任务:test失败,测试被标记为“失败”。我不知道这是怎么回事。
    4.我有时还会收到其他异常
    如果仅通过IntelliJ装订线图标运行测试套件中的第一个测试,则会得到另一个异常:java.lang.ExceptionInInitializerError。我进行了一些挖掘,发现用于读取Scanner类中JSON文件内容的JSONFile<T>会引发NoSuchElementException,因为(出于某种原因)该文件仅在执行此测试期间为。这很奇怪,因为我的:preTest中的自定义build.gradle.kts任务实际上在每个文件中写入了一些内容,而当我在:preTest:test运行之后查看这些文件时,这些内容实际上就在那里。这是完整的控制台输出:
    java.lang.ExceptionInInitializerError
    java.lang.ExceptionInInitializerError
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:315)
        at io.kotest.engine.launcher.ExecuteKt$execute$1.invokeSuspend(execute.kt:37)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlin.coroutines.ContinuationKt.startCoroutine(Continuation.kt:115)
        at io.kotest.engine.launcher.ExecuteKt.future(execute.kt:89)
        at io.kotest.engine.launcher.ExecuteKt.execute(execute.kt:34)
        at io.kotest.engine.launcher.MainKt.main(main.kt:12)
    Caused by: java.util.NoSuchElementException
        at java.base/java.util.Scanner.throwFor(Scanner.java:937)
    
        at java.base/java.util.Scanner.next(Scanner.java:1478)
        at com.example.core.common.JSONFile$Companion.readFile(JSONFile.kt:14)
        at com.example.core.common.JSONFile$Companion.access$readFile(JSONFile.kt:11)
        at com.example.core.common.JSONFile.<init>(JSONFile.kt:27)
        at com.example.core.common.JSONFileTests.<clinit>(JSONFileTests.kt:24)
        ... 8 more
    
    
    Process finished with exit code 0
    
    [java.lang.ExceptionInInitializerError]
    
    现在,我不知道这是问题的一部分还是单独的问题,但只是为了确保我想将其包括在此处。当我在File-> Settings-> Build,Execution,Deployment-> Build Tools-> Gradle中将测试运行程序切换到IntelliJ IDEA时,会发生相同的问题
    而已!现在我的问题是:是什么导致此错误,我该如何解决?
    与运行
  • kotlin / JVM 1.4.10
  • kotest-runner-junit5 4.3.1
  • kotest-assertions-core 4.3.1
  • kotest属性4.3.1
  • kotest-extensions-allure 4.3.1
  • kotest-plugins-pitest 4.3.1
  • gradle 6.7
  • 魅力2.13.6
  • 魅力gradle插件2.8.1
  • pitest gradle插件1.5.1
  • intellij IDEA旗舰版2020.2
  • kotest IntelliJ插件1.1.20-IC-2020.2
  • openJDK 11.0.2
  • 最佳答案

    好像我找到了解决方案。
    问题似乎是Kotest(以及后来的JUnit)想要唯一的测试,这意味着唯一的测试名称。通常,这些问题将由Kotest IntelliJ插件来标记。但是,如果使用测试工厂,则情况会变得更加不透明。我以为include(prefix, testFactory)prefix添加到测试名称中,但事实并非如此。这意味着工厂方法

    private fun <T : JSONModelMarker> echoTests(model: Pair<JSONFile<T>, T>) = funSpec {
        test("Writing to and reading from file should result in the original value") {
            model.first.apply { setAndCommit(model.second) }.get() shouldBe model.second
            model.first.reload()
        }
    }
    
    实际上每次调用时都会创建带有固定标识符的测试。现在,当我通过include()多次包含此测试工厂时,我实际上创建了重复的测试,然后使测试任务崩溃。为了解决这个问题,我刚刚实现了一种功能来替代测试名称,如下所示:
    private fun <T : JSONModelMarker> echoTests(name: String, model: Pair<JSONFile<T>, T>) = funSpec {
        test("$name: Writing to and reading from file should result in the original value") {
            model.first.apply { setAndCommit(model.second) }.get() shouldBe model.second
            model.first.reload()
        }
    }
    
    现在,当我调用include()方法时,我省略了前缀(因为它不相关),并向工厂方法调用添加了唯一的名称(以前是前缀):
    include(echoTests("JSONModel01", m1))
    
    执行完此操作后,该错误不再发生。

    关于unit-testing - Kotest使用java.lang.IllegalArgumentException中断了gradle的:test任务:收到了ID未知的测试失败事件,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/64685933/

    10-10 03:24