Как мокать зависимости в конструкторе Application
Что проверяют
Знаете ли вы, что Application создаёт система, а не вы. Класс указан в манифесте и создаётся через рефлексию конструктором без аргументов, поэтому «передать мок в конструктор» в прямом смысле нельзя. Интервьюер ждёт, что вы это скажете и предложите рабочие способы подмены. Следом спрашивают, как это устроено в Hilt.
Как отвечать
Сначала поправьте постановку: class MyApplication(private val analytics: AnalyticsService) : Application() не стартует на устройстве, приложение упадёт ещё до onCreate(). Дальше варианты:
- вынести логику из
Application: вonCreate()оставить только запуск графа зависимостей, а инициализацию аналитики и SDK перенести в классы, которые принимают зависимости конструктором и тестируются обычным юнит-тестом с MockK или Mockito; - Hilt: приложение помечено
@HiltAndroidApp, а в инструментальных тестах подменяется наHiltTestApplicationчерез свой наследникAndroidJUnitRunnerс переопределённымnewApplication(). Боевой модуль заменяется через@TestInstallInдля всех тестов или@UninstallModulesдля одного, а конкретный мок подкладывается полем с@BindValue; - тестовый наследник: в
Applicationметодopen fun createAnalytics(), в тестовомTestAppон переопределён. В Robolectric такой класс подключается через@Config(application = TestApp::class), в инструментальных тестах через тот жеnewApplication(); AppComponentFactory: с API 28 можно создаватьApplicationсамому и передать зависимости в конструктор, но на практике это редкость.
Где спотыкаются
Пишут конструктор с параметрами и тест, где MyApplication(mock) вызывают вручную. Тест проверяет сценарий, которого в реальном запуске не бывает, а само приложение не стартует.
Вызывают application.onCreate() в обычном JVM-тесте. Классы из android.jar там заглушки и падают на первом платформенном вызове, нужен Robolectric или тест на устройстве.
Забывают про тестовый раннер в Hilt. Без testInstrumentationRunner, указывающего на свой класс, тесты с @HiltAndroidTest падают при старте, потому что приложение осталось боевым, а не HiltTestApplication.