1

I have a problem with Koin & "androidTest". Because androidTest starts the Application I don't need to start Koin by myself in the test.

Now I need to inject a mock service. The problem is, that I inject inside of a method with get() inside of a singleton class and this is not working via constructor injection because the injected object can have different implementations.

My idea was to declare what I need this way:

declare {
        factory<Webservice>(override = true) { mockWebservice }
    }

But this will be applied on all tests. That's why an other test, which checks if the correct class was injected failed.

I also tried to use stopKoin(), startKoin(listOf(appModule)) in the @After method, but with this the dependency injection doesn't work anymore in later tests.

Is there a way to declare the mock only for one test?

Lino
  • 5,084
  • 3
  • 21
  • 39
karuto
  • 1,228
  • 1
  • 10
  • 7

2 Answers2

4

Here is how I do it in my Android Tests:

In a parent test class, I use these methods for setup and teardown:

@Before fun startKoinForTest() {
    if (GlobalContext.getOrNull() == null) {
        startKoin {
            androidLogger()
            androidContext(application)
            modules(appComponent)
        }
    }
}

@After fun stopKoinAfterTest() = stopKoin()

My appcomponent contains all modules needed for the dependency tree.

Then, when I want to mock a dependency for a specific test, I use something like this:

declareMock<TripApi> { given(this.fetch(any())).willReturn(TestData.usaTrip) }

You will need to add a new mock declaration for each test if you wish to swap a dependency with a mock.

Edit: Application is gotten this way:

protected val instrumentationContext: Context = InstrumentationRegistry.getInstrumentation().targetContext
protected val application = instrumentationContext.applicationContext as Application
Sean Blahovici
  • 5,350
  • 4
  • 28
  • 38
2

To declare mock only for one test you can use loadKoinModules()

You can’t call the startKoin() function more than once. But you can use directly the loadKoinModules() functions.

So this way your definition will override default one

loadKoinModules(module {
    factory<Webservice>(override = true) { mockWebservice }
})

Also, don't forget to implement KoinTest interface in you test class

Rohit Karadkar
  • 832
  • 10
  • 18
  • Thanks for the answer but if i do this, an other test in an other class fails: demoMode.activate() val webservice: Webservice = get() assertTrue(webservice is DemoWebservice) – karuto Oct 17 '18 at 05:37