So scoping with Koin DI seem to throw a weird exception when KoinApplication::checkModules() method is called within a unit test. Here is the full code:
import org.koin.core.KoinApplication
import org.koin.core.component.KoinComponent
import org.koin.core.component.KoinScopeComponent
import org.koin.core.component.createScope
import org.koin.core.component.inject
import org.koin.core.context.startKoin
import org.koin.core.logger.Level
import org.koin.core.scope.Scope
import org.koin.dsl.module
import org.koin.test.KoinTest
import org.koin.test.check.checkModules
import org.koin.test.inject
import kotlin.test.BeforeTest
import kotlin.test.Test
class FixScopingTest : KoinTest {
private val component1: Component1 by inject()
private lateinit var koinApp: KoinApplication
@BeforeTest
fun setup() {
koinApp = startKoin {
modules(
module {
single { Component1() }
scope<Component1> {
scoped { Component2() }
}
}
)
// printLogger(Level.DEBUG)
}
}
@Test
fun verifyKoinApp() {
//component1.component2.print()
koinApp.checkModules()
}
}
class Component1 : KoinComponent, KoinScopeComponent {
override val scope: Scope by lazy { createScope(this) }
val component2: Component2 by inject()
}
class Component2 {
fun print() = println("Component2::print()")
}
exception 1:
com.xycompany.xyproj.xypackage.FixScopingTest > verifyKoinApp FAILED
java.lang.IllegalStateException: Missing MockProvider. Please use MockProvider.register() to register a new mock provider
at org.koin.test.mock.MockProvider.getProvider(MockProvider.kt:10)
at org.koin.test.mock.MockProvider.makeMock(MockProvider.kt:23)
at org.koin.test.check.CheckModulesKt.mockSourceValue(CheckModules.kt:102)
at org.koin.test.check.CheckModulesKt.check(CheckModules.kt:95)
at org.koin.test.check.CheckModulesKt.checkAllDefinitions(CheckModules.kt:86)
at org.koin.test.check.CheckModulesKt.checkModules(CheckModules.kt:72)
at org.koin.test.check.CheckModulesKt.checkModules(CheckModules.kt:40)
at org.koin.test.check.CheckModulesKt.checkModules$default(CheckModules.kt:40)
at com.xycompany.xyproj.xypackage.FixScopingTest.verifyKoinApp(FixScopingTest.kt:43)
Second weird issue appears when you uncomment the commented part so we would have usage of scoped components on DEBBUG level logger:
exception 2:
com.xycompany.xyproj.xypackage.FixScopingTest > verifyKoinApp FAILED
java.lang.NoSuchMethodError: 'double kotlin.time.Duration.toDouble-impl(long, java.util.concurrent.TimeUnit)'
at org.koin.core.time.MeasureKt.measureDurationForResult(Measure.kt:41)
at org.koin.core.scope.Scope.get(Scope.kt:189)
at com.xycompany.xyproj.xypackage.FixScopingTest$special$$inlined$inject$default$1.invoke(KoinTest.kt:53)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at com.xycompany.xyproj.xypackage.FixScopingTest.getComponent1(FixScopingTest.kt:20)
at com.xycompany.xyproj.xypackage.FixScopingTest.verifyKoinApp(FixScopingTest.kt:41)
SETTINGS: Kotlin Multiplatform Project (test is run in both Andorid and Common packages with the same problem)
VERSIONS:
koin-core: 3.1.3
koin-android: 3.1.3
Looks like you need to add a
MockProviderRule
when usingscoped
. It's not required if are not using scopes.And for it to work you also need to add this dependency to gradle
https://insert-koin.io/docs/reference/koin-test/checkmodules/#allow-mocking-with-a-junit-rule