Внедрение зависимостей в многопроцессорных приложениях Android
TLDR: я разрабатываю приложение, которое работает в нескольких процессах. В целях тестирования пользовательского интерфейса я хочу внедрить поддельную зависимость API, чтобы приложение, работающее в тестах, не зависело от сетевых взаимодействий, однако в многопроцессорном режиме это, похоже, не работает.
Я использую подход, описанный в этом посте, поэтому я реализовал кастом AndroidJUnitRunner
который создает приложение с фиктивными зависимостями (пусть будет MockApplication
вместо того, чтобы с реальными зависимостями (пусть будет RealApplication
). Это работает, и мое приложение запрашивает интерфейс поддельного API из основного процесса.
Мое приложение, однако, использует несколько процессов, например, есть обработка данных Service
который работает в своем собственном процессе и который только начинается startService
вызов из кода приложения. По какой-то причине этот процесс выполняется с экземпляром RealApplication
, без каких-либо ложных зависимостей.
Можно ли как-нибудь заставить это работать? Я пробовал копаться в коде Android, отвечающем за создание экземпляров приложения, но пока не нашел ничего особенно полезного.
PS Я использую Dagger 2 для DI, но это, вероятно, не очень актуально.
2 ответа
Проблема в том, что ваш пользовательский класс приложения не переопределяет реальный класс в AndroidManifest.xml
,
Вы просто указываете инструментальному тестировщику запустить свой пользовательский класс приложения, но затем, если приложение запускает другой процесс, Android Framework даже не узнает, что ему нужно запустить собственный пользовательский класс приложения вместо реального.
Итак, я бы посоветовал вам переопределить класс приложения в пользовательский класс в AndroidManifest.xml
в течение connectedAndroid
выполнение задачи, в результате ваше приложение будет использовать пользовательский класс, даже не взламывая тестировщика и всякий раз, когда запускаются новые процессы.
Я тоже боролся с этой проблемой, так как мне нужно высмеивать сетевые вызовы, исходящие от Service
началось в своем собственном процессе.
Чтобы использовать пользовательский объект приложения (MockApplication) в каждом процессе вашего приложения во время тестов, решение состоит в том, чтобы внедрить переменную сборки в ваш процесс. AndroidManifest.xml
с помощью manifestPlaceholder.
Я определил два вида продукта в build.gradle:
productFlavors {
mock {
manifestPlaceholders = [application:".MockApplication"]
}
prod {
manifestPlaceholders = [application:".RealApplication"]
}
}
- prod: установит реальный объект Application (RealApplication) в манифест
- mock: установит объект приложения Mock (MockApplication) для имитации сетевых вызовов
В AndroidManifest.xml
используйте переменную application как это:
<application
android:label="@string/app_name"
android:name="${application}">
Теперь, когда вы хотите использовать MockApplication, просто запустите тестирование инструментов с вариантом сборки "mockDebug"