【问题标题】:KotlinTest with Koin: InvocationTargetExceptionKotlinTest 与 Koin:InvocationTargetException
【发布时间】:2020-02-05 15:43:22
【问题描述】:

我无法将 Koin 2.0.1 与 Kotlin-test 3.4.2 一起使用。我得到这样的 InvocationTargetException:

Running koinexample.KoinSampleTests
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.009 sec <<< FAILURE! - in koinexample.KoinSampleTests
koinexample.KoinSampleTests  Time elapsed: 0.009 sec  <<< ERROR!
java.lang.reflect.InvocationTargetException
        at koinexample.KoinSampleTests.getKoin(KoinSampleTests.kt:26)
        at koinexample.KoinSampleTests.<init>(KoinSampleTests.kt:61)

我在 GitHub 上创建了一个重现此错误的小示例: https://github.com/elifarley/kotlin-tests-with-koin-examples

只需执行这些命令来克隆 repo 并运行测试:

git clone https://github.com/elifarley/kotlin-tests-with-koin-examples.git
cd kotlin-tests-with-koin-examples
mvn

这是主要的 Kotlin 文件:

package koinexample

import io.kotlintest.koin.KoinListener
import io.kotlintest.shouldBe
import io.kotlintest.specs.FreeSpec
import org.koin.core.inject
import org.koin.dsl.module
import org.koin.test.KoinTest

data class Stats(var ok: Long = 0, var error: Long = 0)

interface StatsServer {
    fun newError(): Long
}

class StatsServerSimple(private val stats: Stats) : StatsServer {
    override fun newError() = stats.error++
}

val appModule = module {
    single { Stats() }
    single { StatsServerSimple(get()) as StatsServer }
}

class KoinSampleTests : FreeSpec(), KoinTest {

    private val modules = listOf(
        appModule
    )

    override fun listeners() = listOf(KoinListener(modules))

    val statsServer: StatsServer by inject()

    init {

        "Happy path" {
            statsServer.newError() shouldBe 1
        }
    }
}

【问题讨论】:

  • 这不应该被关闭为“它是由无法再复制的错字或问题引起的”,因为虽然这是一个简单的导入错误,但这是 Koin 用户犯的一个非常常见的错误,并且因此,对这个问题有一个答案是有帮助的

标签: unit-testing kotlin koin kotlintest


【解决方案1】:

您的问题似乎是一个简单的导入混淆。

注意你使用的是import org.koin.core.inject,也就是这个函数:

inline fun <reified T> KoinComponent.inject(
        qualifier: Qualifier? = null,
        noinline parameters: ParametersDefinition? = null
): Lazy<T> =
        getKoin().inject(qualifier, parameters)

它需要getKoin 才能工作,因此您无法初始化您的测试(测试类在 Koin 有机会启动侦听器之前已初始化)。

正确的导入是import org.koin.test.inject,转换为:

inline fun <reified T> KoinTest.inject(
    qualifier: Qualifier? = null,
    noinline parameters: ParametersDefinition? = null
): Lazy<T> = lazy { get<T>(qualifier, parameters) }

请注意,这确实是惰性的,因此 Kotest 将有机会在您的测试开始之前初始化 Koin。

修复该导入应该可以解决此问题

【讨论】:

  • 这对于 Koin 2.1.3 也是固定的,所以如果你更新你的依赖,你从哪里得到 inject 扩展并不重要。
【解决方案2】:

似乎您永远不会启动 Koin 应用程序。你需要有

startKoin {
            modules(appModule)
        }

在您的测试方法或规范的beforeSpec/beforeTest 函数调用中。

或者在这里使用类似的东西:

    override fun listeners() = listOf(KoinListener(appModule))

在 kotlintest/kotest 的文档中有描述:https://github.com/Kotest/Kotest/blob/master/doc/extensions.md#koin

【讨论】:

  • 我认为他们实际上是在使用 KoinListener,因此这并没有增加问题
  • 啊,是的。没有发现那条线。我的错。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多