#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. Спасибо! Я поиграл с этой идеей, но мне не понравилось переключаться на другой вкус при тестировании — у меня уже есть два измерения, и я не хотел добавлять больше сложности, но, возможно, это единственный способ пойти здесь.