android - 在多功能模块应用程序中,我在哪里加载和卸载 Koin 模块并保持其可测试性

标签 android kotlin android-fragments android-testing koin

基本上我还没有找到更好的方法来加载/卸载单 Activity 、多模块功能方法的模块。 fragment 附加和分离中模块的加载和卸载效果很好,直到涉及到 UI 测试为止。那么就不可能更换模块来测试模块。这确实工作得很好,但我希望能够以某种方式换入和换出模块以进行测试。

我在我的 fragment 中使用了这种方法

    private val moduleList = arrayListOf(dataModule, viewmodelModule)
    private val loadModules by lazy {
        loadKoinModules(moduleList)
    }
    private fun injectFeatures() = loadModules

 // Loading unloading modules
    override fun onAttach(context: Context) {
        super.onAttach(context)

        injectFeatures()
    }

    override fun onDetach() {
        unloadKoinModules(moduleList)

        super.onDetach()
    }

在我的测试中

  @Before
   fun setUp() {
       loadKoinModules(listOf(testViewModelModule, testDataModule))
       launchFragmentInContainer<MenuFragment>()
   }
val dataModule = module {

    single<IMenuRepository> { ImplMenuRepository(get()) }

    single<NetworkDataSource> { FirebaseDataSource(get()) }

}


val testDataModule = module(override = true) {
    single<IMenuRepository>(override = true) { FakeMenuRepository() }
}

这是我的错误

java.lang.RuntimeException: org.koin.core.error.DefinitionOverrideException: Definition '[Single:'com.nikolam.menu.data.IMenuRepository']' try to override existing definition. Please use override option or check for definition '[Single:'com.nikolam.menu.data.IMenuRepository']'
at androidx.test.runner.MonitoringInstrumentation.runOnMainSync(MonitoringInstrumentation.java:441)
at androidx.test.core.app.ActivityScenario.onActivity(ActivityScenario.java:564)
at androidx.fragment.app.testing.FragmentScenario.internalLaunch(FragmentScenario.java:300)
at androidx.fragment.app.testing.FragmentScenario.launchInContainer(FragmentScenario.java:282)
at com.nikolam.menu.ui.menu.MenuItemsDisplayTest.setUp(MenuItemsDisplayTest.kt:66)
at java.lang.reflect.Method.invoke(Native Method)
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 androidx.test.internal.runner.junit4.statement.RunBefores.evaluate(RunBefores.java:76)
at androidx.test.internal.runner.junit4.statement.RunAfters.evaluate(RunAfters.java:61)
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.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
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 org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:388)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2189)
Caused by: org.koin.core.error.DefinitionOverrideException: Definition '[Single:'com.nikolam.menu.data.IMenuRepository']' try to override existing definition. Please use override option or check for definition '[Single:'com.nikolam.menu.data.IMenuRepository']'
at org.koin.core.scope.ScopeDefinition.save(ScopeDefinition.kt:25)
at org.koin.core.scope.ScopeDefinition.save$default(ScopeDefinition.kt:19)
at org.koin.core.registry.ScopeRegistry.mergeDefinitions(ScopeRegistry.kt:95)
at org.koin.core.registry.ScopeRegistry.declareDefinitions(ScopeRegistry.kt:85)
at org.koin.core.registry.ScopeRegistry.declareScope(ScopeRegistry.kt:75)
at org.koin.core.registry.ScopeRegistry.loadModule(ScopeRegistry.kt:64)
at org.koin.core.registry.ScopeRegistry.loadModules$koin_core(ScopeRegistry.kt:55)
at org.koin.core.Koin.loadModules(Koin.kt:316)
at org.koin.core.context.ContextFunctionsKt.loadKoinModules(ContextFunctions.kt:60)
at com.nikolam.menu.ui.menu.MenuFragment$loadModules$2.invoke(MenuFragment.kt:28)
at com.nikolam.menu.ui.menu.MenuFragment$loadModules$2.invoke(MenuFragment.kt:22)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at com.nikolam.menu.ui.menu.MenuFragment.getLoadModules(Unknown Source:2)
at com.nikolam.menu.ui.menu.MenuFragment.injectFeatures(MenuFragment.kt:31)
at com.nikolam.menu.ui.menu.MenuFragment.onAttach(MenuFragment.kt:79)
at androidx.fragment.app.Fragment.performAttach(Fragment.java:2673)
at androidx.fragment.app.FragmentStateManager.attach(FragmentStateManager.java:263)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1182)
at androidx.fragment.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1255)
at androidx.fragment.app.FragmentTransition.calculateFragments(FragmentTransition.java:1138)
at androidx.fragment.app.FragmentTransition.startTransitions(FragmentTransition.java:136)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2001)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1959)
at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1830)
at androidx.fragment.app.BackStackRecord.commitNow(BackStackRecord.java:297)
at androidx.fragment.app.testing.FragmentScenario$1.perform(FragmentScenario.java:317)
at androidx.fragment.app.testing.FragmentScenario$1.perform(FragmentScenario.java:301)
at androidx.test.core.app.ActivityScenario.lambda$onActivity$2$ActivityScenario(ActivityScenario.java:551)
at androidx.test.core.app.ActivityScenario$$Lambda$4.run(Unknown Source:4)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.app.Instrumentation$SyncRunnable.run(Instrumentation.java:2207)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

如果有人在 Koin 和多功能模块项目上取得了成功,请填写我的信息。任何输入都会非常有帮助!

最佳答案

我知道这是一个相当老的问题,但也许答案可以帮助某人:您必须在声明中添加 override = true ,如下所示:

val dataModule = module {
    single<IMenuRepository>(override = true) { ImplMenuRepository(get()) }
    single<NetworkDataSource>(override = true) { FirebaseDataSource(get()) }
}

从 3.1.0 开始,不再需要此选项,因为他们更改了覆盖策略,现在默认为 true。

关于android - 在多功能模块应用程序中,我在哪里加载和卸载 Koin 模块并保持其可测试性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63540155/

相关文章:

android setOnMenuItemClickListener 未调用

android - 从 Android 应用程序以编程方式调用 Google Now 搜索

android - 如何使用 Retrofit/Kotlin 仅提取一个对象或 Json 文件数组?

java - Android fragment 事务动画在 View 寻呼机上不起作用

android - getFragmentManager().popbackstack() 导致空指针异常

java - Android 如何从 URI 打开 Deezer

java - 多类别测验应用程序

java - 错误 "Required:String Found:String?"Kotlin 和 Android Studio

java - 我似乎无法让我的 fragment 在不崩溃的情况下加载 webview

java - fragment 中使用的 webview 的后退按钮不起作用