如何在所有测试中轻松地将生产 Hilt 模块替换为假冒产品

How to easily replace production Hilt modules with fakes in all tests

我的 Android 产品是充满安装各种产品实现的 Hilt 模块的代码:

@Module
@InstallIn(ApplicationComponent.class)
public abstract class TimeModule {...}
@Module
@InstallIn(ApplicationComponent.class)
public abstract class DatabaseModule {...}

在我所有的仪器测试中,我想用假货替换那些绑定。我的测试代码库包含绑定假实现的模块,但是让两个模块提供相同的 class 显然会导致编译时错误。

Hilt 文档建议使用 @UninstallModule(),但这意味着我必须在每个测试中为每个生产模块添加 UninstallModule。这似乎是错误的做法。

通常如何用假模块替换生产模块?有没有一种方法可以像 Guice 那样从另一个模块安装模块,这样我就可以从我的所有生产模块中删除 @InstallIn,而只需要一个 ProductionModule 来安装所有单独的模块?这将使在测试中仅卸载一个模块变得更容易。

How would one normally replace production modules with fake modules?

大概是正常的做法,就像文档中用 UninstallModule 注释说的那样。但这里有一个替代方案,我喜欢使用它,使用构建风格:

我喜欢组织我的项目,所以有 mocklive 两种风格。我的应用程序模块中有 3 个文件夹:src/main/kotlin 包含 Activities、Fragments 等...,src/mock/kotlin 我的假绑定所在的位置,最后 src/live/kotlin 我的真实生产绑定所在的位置。

这是我 app 级别 build.gradle.kts 的相关配置:

android {
  productFlavors {
    flavorDimensions("environment")
    register("mock") {
      dimension = "environment"
    }

    register("dev") {
      dimension = "environment"
    }

    register("prod") {
      dimension = "environment"
    }

    sourceSets {
      getByName("mock").java.srcDir("src/mock/kotlin")
      getByName("dev").java.srcDir("src/live/kotlin")
      getByName("prod").java.srcDir("src/live/kotlin")
    }
  }
}

项目结构概览

直播里面InteractorModule:

@Module
@InstallIn(ApplicationComponent::class)
abstract class InteractorModule {
  @Binds
  abstract fun bindTodoInteractor(interactor: TodoInteractorImpl): TodoInteractor
}

里面FakeInteractorsModule:

@Module
@InstallIn(ApplicationComponent::class)
abstract class InteractorModule {
  @Binds
  abstract fun bindTodoInteractor(interactor: TodoInteractorFake): TodoInteractor
}

现在您可以使用构建变体选项卡在接口的真实实现和模拟实现之间切换。因此,如果你想在你的仪器测试中使用你的假货,请使用模拟风格,而 运行 测试。

这种方法的一个好处是,通过更改构建变体,您可以在使用伪造的仪器测试和使用实时实现之间切换。相反,您可以在实际应用程序中使用您的假实现,如果您只想使用模拟数据试用该应用程序,这可能很好。

我希望这至少能促进一些关于如何解决“一个接口的两种实现”困境的想法!