Why is Koin scoping feature not working properly?

770 views Asked by At

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

1

There are 1 answers

0
drruggeri On

Looks like you need to add a MockProviderRule when using scoped. It's not required if are not using scopes.

@get:Rule
val mockProvider = MockProviderRule.create { clazz ->
    // Mock with your framework here given clazz 
    // e.g: Mockito.mock(clazz.java)
}

And for it to work you also need to add this dependency to gradle

testImplementation "io.insert-koin:koin-test-junit4:3.1.6"

https://insert-koin.io/docs/reference/koin-test/checkmodules/#allow-mocking-with-a-junit-rule