Kotest v4.5.0で同名のテストが実行可能になった

Kotestの最新バージョンはv5.3.0(2022年5月3日リリース)なので、何をいまさら...という感じですが。

 

 

[Kotest]

KotestはKotlinのテストフレームワークである。

kotest.io

 

JavaScriptのテストライブラリっぽくdescribe()を使うこともできるし、BDDっぽくgiven/when/thenのスタイルでテストを実装することもできる。

kotest.io

 

KotestオリジナルのStringSpecを使うことが多いが、これだとネストしたテストを書くことができないので、FunSpecなども使う。

 

[Kotest v.4.4.3以前の挙動]

Kotest v.4.4.3以前のバージョンでは、次のようなテストは失敗していた。

 

import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe

class SameTestName: StringSpec({
    "test 1" {
        "test".length shouldBe 4
    }

    "test 1" {
        "test".length shouldBe 4
    }
})

 

実行すると、次のようなエラーが表示されてテストが失敗する。

Could not create instance of class kotest.sandbox.SameTestName
io.kotest.core.SpecInstantiationException: Could not create instance of class kotest.sandbox.SameTestName
	at io.kotest.engine.spec.InstantiateSpecKt.javaReflectNewInstance(instantiateSpec.kt:37)
	at io.kotest.engine.spec.InstantiateSpecKt.createAndInitializeSpec(instantiateSpec.kt:22)
	at io.kotest.engine.spec.SpecExecutor.createInstance(SpecExecutor.kt:53)
	at io.kotest.engine.spec.SpecExecutor.execute(SpecExecutor.kt:40)
	at io.kotest.engine.launchers.DefaultSpecLauncher$sequential$$inlined$forEach$lambda$1$1.invokeSuspend(DefaultSpecLauncher.kt:56)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
	at kotlin.reflect.jvm.internal.calls.CallerImpl$Constructor.call(CallerImpl.kt:41)
	at kotlin.reflect.jvm.internal.KCallableImpl.call(KCallableImpl.kt:108)
	at io.kotest.engine.spec.InstantiateSpecKt.javaReflectNewInstance(instantiateSpec.kt:35)
	... 9 more
Caused by: io.kotest.core.DuplicatedTestNameException: Cannot create test with duplicated name test 1
	at io.kotest.core.spec.DslDrivenSpec.addRootTest(DslDrivenSpec.kt:105)
	at io.kotest.core.spec.DslDrivenSpec.addTest(DslDrivenSpec.kt:98)
	at io.kotest.core.spec.style.scopes.RootTestRegistration$Companion$from$2.addTest(RootTestRegistration.kt:81)
	at io.kotest.core.spec.style.scopes.RootTestRegistration$DefaultImpls.addTest(RootTestRegistration.kt:33)
	at io.kotest.core.spec.style.scopes.RootTestRegistration$Companion$from$2.addTest(RootTestRegistration.kt:72)
	at io.kotest.core.spec.style.scopes.StringSpecRootScope$DefaultImpls.invoke(StringSpecRootScope.kt:55)
	at io.kotest.core.spec.style.StringSpec.invoke(stringSpec.kt:34)
	at kotest.sandbox.SameTestName$1.invoke(SameNameTest.kt:11)
	at kotest.sandbox.SameTestName$1.invoke(SameNameTest.kt:6)
	at io.kotest.core.spec.style.StringSpec.(stringSpec.kt:37)
	at kotest.sandbox.SameTestName.(SameNameTest.kt:6)
	... 16 more


kotest.sandbox.SameTestName > executionError FAILED
    io.kotest.core.SpecInstantiationException at instantiateSpec.kt:37
        Caused by: java.lang.reflect.InvocationTargetException at NativeConstructorAccessorImpl.java:-2
            Caused by: io.kotest.core.DuplicatedTestNameException at SameNameTest.kt:11
2 tests completed, 1 failed, 1 skipped
> Task :kotest4:test FAILED

 

[Kotest v4.5.0の新機能]

v4.4.3以前の同名テストが失敗する問題は、Kotest v4.5.0のリリース(2021年5月5日)で追加された機能によって解消された。

github.com

 

v.4.5.0で先ほどと同じテストを実行すると、以下のように成功する。

 

先ほどのテストの例ではわざとテストケースを同名にしているが、本来この機能はデータドリブンテストでデータクラスを利用していない場合にテストが同名になる問題を解決するために導入された(自分もそれで引っかかったことがある)。

github.com

 

プルリクを見る限り、以下のように設定すれば同名テストがエラーになるように読めたのだが、うまく動作しなかった...謎。

object ProjectConfig : AbstractProjectConfig() {
    override val duplicateTestNameMode = DuplicateTestNameMode.Error
}

 

[まとめ]

  • Kotest v4.4.3以前では同名のテストがエラーになっていた
  • Kotest v4.5.0以降では同名のテストがあった場合、自動的にテスト名が修正されるようになった
  • Kotest v4.5.0以降でも、以前のように同名のテストをエラーにできるはずだが設定してもうまく動かなかった
  • サンプルコードは以下のリポジトリにまとめてある

github.com