Android 使用 KodeIn 进行仪器化测试

Android Instrumented tests with KodeIn

我们有一个 Android 应用程序正在为视图层使用 compose,我们正在使用 Kodein 进行所有依赖项注入。

我有一个 BaseApplication class,它是 DIAware:

class BaseApplication : Application(), DIAware {
    override val di: DI = DI.lazy {
        import(modules) // modules defined in respective packages
    }
}

我还有一个 MainActivity 和一个导航图来管理各种可组合项之间的导航。

问题: 如何在 MainActivity 的插桩测试中正确覆盖这些模块?

@RunWith(AndroidJUnit4::class)
class MainActivityTest {
    @get:Rule
    val composeTestRule = createAndroidComposeRule<MainActivity>()

    val moduleOverrides = DI.Module(allowSilentOverride = true) {
        // add bindings for fakes w/ allowOverride = true
    }
    
    @Before
    fun setup() {
        val application =
            ApplicationProvider.getApplicationContext() as BaseApplication

        // how can I override the BaseApplication modules for my test?
    }

}

我似乎找不到关于此事的任何明确语言,感觉我遗漏了一些非常明显的东西。非常感谢任何帮助。

有几种方法可以实现。一般的方法是覆盖实际的模块,如

val someParrentKodeinModule...

val mockModule = Kodein {
    extend(someParrentKodeinModule, allowOverride = true)
    bind<Foo>(overrides = true) with provider { Foo2() }
}

or 

val kodein = Kodein {
    /* ... */
    import(testsModule, allowOverride = true)
}

其中 testsModule 是某个模块,它已经定义了所有需要的模拟组件,这些组件将在主组件中被覆盖。 你的方法也不错。关键是用所需的 DI 替换您的 DI - 这可以在您的应用程序中制作 DI - var 而不是 val 并为其分配新值。但是你必须放弃 DIAware

class BaseApplication : Application() {
    var di: DI = DI.lazy {
        import(modules) // modules defined in respective packages
    }
}

@Before
    fun setup() {
        val application =
            ApplicationProvider.getApplicationContext() as BaseApplication

       application.di = moduleOverrides
    }

类似的东西。

并且通常不建议在 App class 内对应用使用单个 DI。为您要测试的应用程序的每个组件使用专用模块