InsertKoinIO / koin

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

KoinApplication.checkModules() is always successfull #653

Closed robertpicsart closed 4 years ago

robertpicsart commented 5 years ago

I'm trying to create a unit test to check if all the dependencies are written in the modules, but checkModules() is always successful, no matter how many dependencies are there in the modules.

Is there some other way to test this?

erickok commented 5 years ago

What arguments are you passing to the function? You should apss in the list of all modules you want to check.

robertpicsart commented 5 years ago

koinApp = startKoin { modules(NewsApp().modules) }

The code is like this. I have several modules. Now this test is successful. Then I'm commenting one dependency, and it's again successful.

erickok commented 5 years ago

You should pass the list of modules to test into the checkModules() function, not start Koin (and expect the loaded modules to be checked).

robertpicsart commented 5 years ago

koinApplication { modules(appModule) }.checkModules() this is how it written in the documentation.

The checkModules() is not accepting type List

erickok commented 5 years ago

Yes it's an extention function, that wasn't clear in my wording. It should look something like this:

        koinApplication {
            modules(...)
        }.checkModules()
robertpicsart commented 5 years ago

If I use koinApplication I receive an error that Koin Application is not started.

If I use startKoin then it doesn't matter what dependencies are in my modules. The test is always passing.

erickok commented 5 years ago

Can you provide a (minimal) reproducable example? Are you doing this in a unit test, an instrumented test (if on Android) or Espresso test?

There are a range of examples here: https://github.com/InsertKoinIO/koin/blob/master/koin-projects/koin-test/src/test/kotlin/org/koin/test/CheckModulesTest.kt

robertpicsart commented 5 years ago

This is an Android Unit test

`class KoinDependenciesTest : KoinTest {

@Test
fun `check all dependencies`() {
    koinApplication { 
        modules(NewsApp().modules)
    }.checkModules()
}

}`

robertpicsart commented 5 years ago

and this is the error `org.koin.core.error.InstanceCreationException: Could not create instance for [type:Single,primary_type:'com.robertlevonyan.domain.interactors.article.GetSearchedArticlesInteractor']

at org.koin.core.instance.DefinitionInstance.create(DefinitionInstance.kt:61)
at org.koin.core.instance.SingleDefinitionInstance.get(SingleDefinitionInstance.kt:40)
at org.koin.core.definition.BeanDefinition.resolveInstance(BeanDefinition.kt:70)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:165)
at org.koin.core.scope.Scope.get(Scope.kt:128)
at org.koin.core.Koin.get(Koin.kt:107)
at org.koin.test.check.CheckModulesKt.checkMainDefinitions(CheckModules.kt:60)
at org.koin.test.check.CheckModulesKt.checkModules(CheckModules.kt:38)
at org.koin.test.check.CheckModulesKt.checkModules(CheckModules.kt:25)
at org.koin.test.check.CheckModulesKt.checkModules$default(CheckModules.kt:25)
at com.robertlevonyan.newsfeed.KoinDependenciesTest.check all dependencies(KoinDependenciesTest.kt:31)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Caused by: java.lang.IllegalStateException: KoinApplication has not been started at org.koin.core.context.GlobalContext.get(GlobalContext.kt:37) at org.koin.core.KoinComponent$DefaultImpls.getKoin(KoinComponent.kt:32) at com.robertlevonyan.domain.usecases.article.GetSearchedArticlesUseCase.getKoin(GetSearchedArticlesUseCase.kt:8) at com.robertlevonyan.domain.usecases.article.GetSearchedArticlesUseCase.(GetSearchedArticlesUseCase.kt:16) at com.robertlevonyan.domain.di.ModulesKt$articleInteractorModule$1$1.invoke(Modules.kt:14) at com.robertlevonyan.domain.di.ModulesKt$articleInteractorModule$1$1.invoke(Modules.kt) at org.koin.core.instance.DefinitionInstance.create(DefinitionInstance.kt:54) ... 32 more`

erickok commented 5 years ago

I don't know the details of your code but it looks like you directly access Koin from GetSearchedArticlesUseCase in the constructor or (field) initializer? The checkModuels function will try to instantiate all your definitions and it fails here.

robertpicsart commented 5 years ago

Okay I've changed it and now there is direct access to Koin. But I still cannot test if all the dependencies are present. This works only if there is some usage of the dependency in another one with get.

I cannot test for example, if all dependencies for my view models are present

erickok commented 5 years ago

I expect the reverse - you can test only if you are NOT directly using get - which you shouldn't, you should inject all dependencies via constructor (or perhaps with a by lazy in special cases).

robertpicsart commented 5 years ago

Yes all the dependencies are injected via constructor, except view models

robertpicsart commented 5 years ago

Is there a way to test by viewModel() injection? I mean the existence of dependency.

erickok commented 5 years ago

If a viewmodel is declared in your model, it's dependencies will be tested (if they exist and themselves are instantiatable).

Op ma 25 nov. 2019 16:05 schreef Robert Levonyan notifications@github.com:

Is there a way to test by viewModel() injection? I mean the existence of dependency.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/InsertKoinIO/koin/issues/653?email_source=notifications&email_token=AABP6ZNKQ5AFXKAWBTN5DB3QVPSTDA5CNFSM4JRIJW7KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEFCWH7A#issuecomment-558195708, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABP6ZNHVONIQYDUEPFSA7DQVPSTDANCNFSM4JRIJW7A .

robertpicsart commented 5 years ago

viewmodels are injected to fragments. that is the only place where they are used