Search code examples
androidkotlinkodein

How to inject test overrides into the default dependency graph?


I would like to inject mocked overrides into my Android instrumentation tests using Kodein. I don't know which is the optimal approach to do this. Here's what I have in mind:

  • My app uses a KodeinAware application class. The served Kodein instance holds all dependencies required by my app.
  • In my tests I would like to inject mocked overrides for specific dependencies to test behavior of the app in various situations.
  • Overrides should be different for each test, and should be injected before/while the test runs.

Is the configurable Kodein extension sensible in this situation, or is there a simpler, better suited approach (and if so, which)?


Solution

  • I am now using the ConfigurableKodein inside my custom App class.

    class App : Application(), KodeinAware {
        override val kodein = ConfigurableKodein()
    
        override fun onCreate() {
            super.onCreate()
    
            // A function is used to create a Kodein module with all app deps.
            kodein.addImport(appDependencies(this))
        }
    }
    
    // Helper for accessing the App from any context.
    fun Context.asApp() = this.applicationContext as App
    

    Inside my AppTestRunner class, I declare the configuration to be mutable. That way I can reset it's configuration between each and every test.

    class AppTestRunner : AndroidJUnitRunner() {
        override fun callApplicationOnCreate(app: Application) {
            app.asApp().kodein.mutable = true
            super.callApplicationOnCreate(app)
        }
    }
    

    I have created a JUnit rule that reset the dependency graph before every test.

    class ResetKodeinRule : ExternalResource() {
        override fun before() {
            val app = InstrumentationRegistry.getInstrumentation().targetContext.asApp()
            app.kodein.clear()
            app.kodein.addImport(appDependencies(app))
        }
    }
    

    In my tests I can now retrieve the App.kodein instance and inject mocks that override dependencies of the original graph. The only thing that needs to be guaranteed is that the tested activity is launched after configuring mocks, or behavior is not predictable.