Как легко заменить производственные модули Hilt подделками во всех тестах

#android #dependency-injection #dagger-hilt

#Android #внедрение зависимостей #кинжал-рукоять

Вопрос:

Мой Android-продукт — это код, полный модулей Hilt, которые устанавливают различные производственные реализации:

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

Во всех моих инструментальных тестах я хотел бы заменить эти привязки подделками. Моя тестовая кодовая база включает модули, которые связывают поддельные реализации, но наличие двух модулей, предоставляющих один и тот же класс, очевидно, вызывает ошибки во время компиляции.

Документация Hilt рекомендует использовать @UninstallModule() , но это означает, что мне придется добавлять UninstallModule для каждого отдельного производственного модуля в каждом отдельном тесте. Это кажется неправильным подходом.

Как обычно можно заменить производственные модули поддельными модулями? И есть ли способ установить модули из другого модуля, как это делает Guice, чтобы я мог удалить @InstallIn все свои производственные модули и вместо этого просто иметь тот ProductionModule , который устанавливает все отдельные модули? Это упростило бы удаление одного модуля в тестах.

Ответ №1:

Как обычно можно заменить производственные модули поддельными модулями?

Вероятно, как это обычно делается, похоже на документацию, указанную в UninstallModule аннотации. Но вот альтернатива, которую мне нравится использовать, используя варианты сборки:

Мне нравится организовывать свой проект, поэтому есть mock и live вкусы. И внутри моего модуля приложения есть 3 папки: src/main/kotlin с действиями, фрагментами и т. Д., 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")
    }
  }
}

  

Обзор структуры проекта

Обзор структуры проекта

Внутри live 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
}
  

Итак, теперь вы можете использовать вкладку «Вариант сборки» для переключения между реальной и фиктивной реализациями ваших интерфейсов. Поэтому, если вы хотите использовать свои подделки в своих инструментальных тестах, используйте макет во время выполнения тестов.

Одним из преимуществ этого метода является то, что, изменив вариант сборки, вы можете переключаться между вашими инструментальными тестами с использованием ваших подделок и использованием реальных реализаций. И наоборот, вы можете использовать свои поддельные реализации внутри фактического приложения, что может быть неплохо, если вы просто хотите опробовать приложение с фиктивными данными.

Я надеюсь, что это немного помогло, по крайней мере, продвинуть некоторые идеи о том, как вы можете решить эту дилемму «две реализации для одного интерфейса»!

Комментарии:

1. Спасибо! Я поиграл с этой идеей, но мне не понравилось переключаться на другой вкус при тестировании — у меня уже есть два измерения, и я не хотел добавлять больше сложности, но, возможно, это единственный способ пойти здесь.