InsertKoinIO / koin

Koin - a pragmatic lightweight dependency injection framework for Kotlin & Kotlin Multiplatform
https://insert-koin.io
Apache License 2.0
8.98k stars 710 forks source link

createdAtStart and checkModules not working #1730

Closed ivsokol-ht closed 7 months ago

ivsokol-ht commented 9 months ago

Hi,

I have module definition like this:

` val scModule = module { includes(configurationModule, telemetryModule)

single<IServiceCatalogRepository>(named(SERVICE_CATALOG_REPOSITORY)) {
    ServiceCatalogRepository()
}

single<IServiceCatalogService>(named(SERVICE_CATALOG_SERVICE)) {
    ServiceCatalogService(
        get(named(SERVICE_CATALOG_REPOSITORY)),
    )
} withOptions {
    createdAtStart()
}

} `

and test code like this

` class ModuleTest : FunSpec(), KoinTest { override fun extensions() = listOf(KoinExtension(scModule))

init {

    test("SC test DI defined") {
        koinApplication {
            modules(scModule)
            checkModules()
        }
    }
}

} `

when I run test, they fail with org.koin.core.error.InstanceCreationException: Could not create instance for '[Singleton:'hr.ht.rnd.dps.sqm.modules.sc.IServiceCatalogService',qualifier:ServiceCatalogService]' at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:59) at org.koin.core.instance.SingleInstanceFactory.create(SingleInstanceFactory.kt:46) at org.koin.core.instance.SingleInstanceFactory$get$1.invoke(SingleInstanceFactory.kt:53) at org.koin.core.instance.SingleInstanceFactory$get$1.invoke(SingleInstanceFactory.kt:51) at org.koin.mp.KoinPlatformTools.synchronized(KoinPlatformTools.kt:20) at org.koin.core.instance.SingleInstanceFactory.get(SingleInstanceFactory.kt:51) at org.koin.core.registry.InstanceRegistry.createEagerInstances(InstanceRegistry.kt:96) at org.koin.core.registry.InstanceRegistry.createAllEagerInstances$koin_core(InstanceRegistry.kt:64) at org.koin.core.Koin.createEagerInstances(Koin.kt:339) at org.koin.core.KoinApplication.createEagerInstances(KoinApplication.kt:74) at org.koin.dsl.KoinApplicationKt.koinApplication(KoinApplication.kt:31) at hr.ht.rnd.dps.sqm.modules.sc.ModuleTest$1.invokeSuspend(ModuleTest.kt:15) at hr.ht.rnd.dps.sqm.modules.sc.ModuleTest$1.invoke(ModuleTest.kt) at hr.ht.rnd.dps.sqm.modules.sc.ModuleTest$1.invoke(ModuleTest.kt) at io.kotest.core.spec.style.scopes.RootScopeKt$addTest$1.invokeSuspend(RootScope.kt:36) at io.kotest.core.spec.style.scopes.RootScopeKt$addTest$1.invoke(RootScope.kt) at io.kotest.core.spec.style.scopes.RootScopeKt$addTest$1.invoke(RootScope.kt) at io.kotest.engine.test.TestCaseExecutor$execute$innerExecute$1.invokeSuspend(TestCaseExecutor.kt:83) at io.kotest.engine.test.TestCaseExecutor$execute$innerExecute$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.TestCaseExecutor$execute$innerExecute$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.interceptors.CoroutineDebugProbeInterceptor.intercept(CoroutineDebugProbeInterceptor.kt:29) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:92) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.interceptors.InvocationTimeoutInterceptor$intercept$3.invokeSuspend(InvocationTimeoutInterceptor.kt:43) at io.kotest.engine.test.interceptors.InvocationTimeoutInterceptor$intercept$3.invoke(InvocationTimeoutInterceptor.kt) at io.kotest.engine.test.interceptors.InvocationTimeoutInterceptor$intercept$3.invoke(InvocationTimeoutInterceptor.kt) at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturnIgnoreTimeout(Undispatched.kt:89) at kotlinx.coroutines.TimeoutKt.setupTimeout(Timeout.kt:151) at kotlinx.coroutines.TimeoutKt.withTimeoutOrNull(Timeout.kt:107) at io.kotest.engine.test.interceptors.InvocationTimeoutInterceptor.intercept(InvocationTimeoutInterceptor.kt:42) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:92) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.TestInvocationInterceptor$intercept$2$3.invokeSuspend(TestInvocationInterceptor.kt:36) at io.kotest.engine.test.TestInvocationInterceptor$intercept$2$3.invoke(TestInvocationInterceptor.kt) at io.kotest.engine.test.TestInvocationInterceptor$intercept$2$3.invoke(TestInvocationInterceptor.kt) at io.kotest.mpp.ReplayKt.replay(replay.kt:18) at io.kotest.engine.test.TestInvocationInterceptor$intercept$2.invokeSuspend(TestInvocationInterceptor.kt:31) at io.kotest.engine.test.TestInvocationInterceptor$intercept$2.invoke(TestInvocationInterceptor.kt) at io.kotest.engine.test.TestInvocationInterceptor$intercept$2.invoke(TestInvocationInterceptor.kt) at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:78) at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:264) at io.kotest.engine.test.TestInvocationInterceptor.intercept(TestInvocationInterceptor.kt:30) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:92) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.interceptors.TimeoutInterceptor.intercept(TimeoutInterceptor.kt:33) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:92) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.interceptors.BlockedThreadTimeoutInterceptor.intercept(BlockedThreadTimeoutInterceptor.kt:74) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:92) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.interceptors.CoroutineLoggingInterceptor.intercept(CoroutineLoggingInterceptor.kt:30) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:92) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.interceptors.SoftAssertInterceptor.intercept(SoftAssertInterceptor.kt:27) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:92) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.interceptors.AssertionModeInterceptor.intercept(AssertionModeInterceptor.kt:25) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:92) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.interceptors.LifecycleInterceptor.intercept(LifecycleInterceptor.kt:51) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:92) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.interceptors.EnabledCheckInterceptor.intercept(EnabledCheckInterceptor.kt:31) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:92) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.interceptors.TestCaseExtensionInterceptor$intercept$2.invokeSuspend(TestCaseExtensionInterceptor.kt:24) at io.kotest.engine.test.interceptors.TestCaseExtensionInterceptor$intercept$2.invoke(TestCaseExtensionInterceptor.kt) at io.kotest.engine.test.interceptors.TestCaseExtensionInterceptor$intercept$2.invoke(TestCaseExtensionInterceptor.kt) at io.kotest.engine.test.TestExtensions$intercept$execute$1$1$1.invokeSuspend(TestExtensions.kt:149) at io.kotest.engine.test.TestExtensions$intercept$execute$1$1$1.invoke(TestExtensions.kt) at io.kotest.engine.test.TestExtensions$intercept$execute$1$1$1.invoke(TestExtensions.kt) at io.kotest.koin.KoinExtension.intercept(KoinExtension.kt:61) at io.kotest.engine.test.TestExtensions$intercept$execute$1$1.invokeSuspend(TestExtensions.kt:146) at io.kotest.engine.test.TestExtensions$intercept$execute$1$1.invoke(TestExtensions.kt) at io.kotest.engine.test.TestExtensions$intercept$execute$1$1.invoke(TestExtensions.kt) at io.kotest.engine.test.TestExtensions.intercept(TestExtensions.kt:154) at io.kotest.engine.test.interceptors.TestCaseExtensionInterceptor.intercept(TestCaseExtensionInterceptor.kt:24) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:92) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.interceptors.CoroutineErrorCollectorInterceptor$intercept$3.invokeSuspend(CoroutineErrorCollectorInterceptor.kt:28) at io.kotest.engine.test.interceptors.CoroutineErrorCollectorInterceptor$intercept$3.invoke(CoroutineErrorCollectorInterceptor.kt) at io.kotest.engine.test.interceptors.CoroutineErrorCollectorInterceptor$intercept$3.invoke(CoroutineErrorCollectorInterceptor.kt) at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:78) at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:167) at kotlinx.coroutines.BuildersKt.withContext(Unknown Source) at io.kotest.engine.test.interceptors.CoroutineErrorCollectorInterceptor.intercept(CoroutineErrorCollectorInterceptor.kt:27) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:92) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt) at io.kotest.engine.test.interceptors.CoroutineDispatcherFactoryInterceptor$intercept$4.invokeSuspend(coroutineDispatcherFactoryInterceptor.kt:57) at io.kotest.engine.test.interceptors.CoroutineDispatcherFactoryInterceptor$intercept$4.invoke(coroutineDispatcherFactoryInterceptor.kt) at io.kotest.engine.test.interceptors.CoroutineDispatcherFactoryInterceptor$intercept$4.invoke(coroutineDispatcherFactoryInterceptor.kt) at io.kotest.engine.concurrency.FixedThreadCoroutineDispatcherFactory$withDispatcher$4.invokeSuspend(FixedThreadCoroutineDispatcherFactory.kt:53) 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:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:833) Caused by: org.koin.core.error.ClosedScopeException: Scope '_root_' is closed at org.koin.core.scope.Scope.resolveInstance(Scope.kt:221) at org.koin.core.scope.Scope.get(Scope.kt:210) at hr.ht.rnd.dps.sqm.modules.sc.ServiceCatalogModuleKt$scModule$1$2.invoke(ServiceCatalogModule.kt:44) at hr.ht.rnd.dps.sqm.modules.sc.ServiceCatalogModuleKt$scModule$1$2.invoke(ServiceCatalogModule.kt:31) at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:52) ... 108 more

when I remove withOptions { createdAtStart() } from SERVICE_CATALOG_SERVICE singleton, test passes

Seams like createdAtStart() and checkModules() combination is not working.

I am using koin-core:3.3.3

Thank you for the support.

JohnyDaDeveloper commented 9 months ago

This issue also occures when createdAtStart is set through

single<SomeInterface>(
    createdAtStart = true,
) {
    SomeInterfaceImplementation(
        get(),
        get(),
    )
}
arnaudgiuliani commented 8 months ago

createdAtStart shouldn't do any difference in your test. But worth to check this option yes 🤔

arnaudgiuliani commented 7 months ago

Yes, finally : createAtStart confilct with checkModules. You can run your config like that:

val modules = module {
    single { Simple.ComponentB(get()) } withOptions { createdAtStart() }
}

koinApplication(createEagerInstances = false) {
    modules(modules)
    checkModules {
        withInstance<Simple.ComponentA>()
    }
}

Use createEagerInstances = false in your koinApplication.