【问题标题】:How to provide test/mock dependencies for Dagger2 @Subcomponent?如何为 Dagger2 @Subcomponent 提供测试/模拟依赖?
【发布时间】:2022-12-10 07:35:45
【问题描述】:

在不同的教程中,我看到了如何将 @Component 的依赖项替换为 mock 或 fakes。为此,可以使 @Component 的测试变体扩展常规版本。但是我还没有找到如何对@Subcomponent 做同样的事情。

这是我的设置。零件:

@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {
    fun plus(userModule: UserModule): UserComponent
    ...
}

组件的测试版本:

@Singleton
@Component(modules = [TestAppModule::class])
interface TestAppComponent: AppComponent

子组件:

@UserScope
@Subcomponent(modules = [UserModule::class])
interface UserComponent

用法:

@Before
fun setUp() {
    MockKAnnotations.init(this)

    val loginManagerMock = mockk<LoginManager>()

    val testAppModule = TestAppModule(
        context = app,
        loginManager = loginManagerMock
    )

    val appComponent = DaggerTestAppComponent.builder()
        .testAppModule(testAppModule)
        .build()

    val testUserModule = TestUserModule(
        context = app,
        userEmail = "testing@mail.com",
        pdaRepository = pdaRepositoryMock
    )

    val userComponent = appComponent.plus(testUserModule) // this is not working

    every { loginManagerMock.userComponent } returns userComponent

    app.appComponent = appComponent

}

问题是我不能像实例化@Component 那样实例化@Subcomponent。我必须使用 AppComponent 的 plus(userModule: UserModule): UserComponent 方法。 TestAppModule 不可能扩展 AppModule 并覆盖 @Provides 方法。

如果有人能告诉我如何用模拟或假货替换@Subcomponent 的 UserModule 提供的依赖项,我将不胜感激?

【问题讨论】:

    标签: unit-testing mocking dagger-2 dagger


    【解决方案1】:

    这里的一个困难是您通过在组件本身上包含一个子组件“工厂方法”来使用 legacy method of subcomponent creation。通过这种方式,具体的子组件类型直接通过组件接口来表达,这使得你所说的组件子类化变得更加困难。

    你有几个选择:

    选项1: 子类UserComponent成为TestUserComponent,重写TestAppComponent.plus返回TestUserComponent而不是Component。一方面,您的覆盖将起作用,因为返回值比您重载的方法更具体:在子类或子接口中,为了多态兼容性,参数可以相等或更一般,返回值可以相等或更具体。但是,为了多态性,传递的模块集必须相同。您可以将 UserModule 拆分为三个模块,可实例化的 UserParameterModule、生产 UserProductionModule 和提供覆盖的仅测试 UserTestModule,但所有这些模块很快就会变得非常毛茸茸。

    选项 2:使用 Module.subcomponents 而不是 plus 方法指定 UserComponent。不要公开您的 plus 方法,而是公开您创建的 UserComponent.Builder 或 UserComponent.Factory 以替换 plus 方法。 (这需要重构一些生产代码。)虽然我没试过,但你可能能够将 UserComponent.Factory 绑定到匹配的 TestUserComponent.Factory,尽管与选项 1 一样,您仍然需要重构模块,因为您仍在尝试使工厂方法以多态方式工作。

    选项 3:因为模块不同,所以不要试图让你的生产图和测试图以完全相同的方式工作。相反,切换到上面的 Module.subcomponents 并创建一个“UserComponentCreator”接口,这也需要重构生产代码,但允许您与生产中的自己的 ProductionUserComponentCreator 实例和测试中的 TestUserComponentCreator 进行交互。这是 Java 臭名昭著的那种抽象和间接,但这意味着您可以对 TestUserComponentCreator 实际为您做的事情保留很多控制权。

    选项 4:使用不同的测试接缝,例如生成一个完全不同的组件,在其上安装模拟 UserComponent 并模拟其所有 AppComponent 依赖项,或者提供由 Kotlin delegation 创建的 UserComponent 而不是使用 @Provides 方法。

    附带说明一下,在混合使用真假组件创建 Dagger 图时要小心,因为确定哪些部分是真实的哪些部分是假的可能要困难得多。您不希望编写无意中测试您的模拟的单元测试,而生产中的实际系统由于缺乏实际测试而超出规范。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-25
      • 1970-01-01
      • 1970-01-01
      • 2016-02-19
      相关资源
      最近更新 更多