Как устроена автоматизация тестов и интеграционное тестирование
Что проверяют
Знаете ли вы, какие тесты в Android идут на JVM, а какие требуют устройства, и что именно проверяет интеграционный тест. Следом часто спрашивают, как тестировать Room, сетевой слой и корутины и как не утонуть в нестабильных UI-тестах.
Как отвечать
Разложите по пирамиде и по папкам проекта:
- локальные тесты (
src/test): JUnit, MockK или Mockito, выполняются на JVM за секунды. Сюда идут ViewModel, use case, мапперы. Корутины проверяются черезkotlinx-coroutines-test:runTest,StandardTestDispatcher, подменаDispatchers.Main, а Flow удобно проверять библиотекой Turbine; - Robolectric: гоняет код, зависящий от Android SDK, на JVM без эмулятора;
- инструментальные тесты (
src/androidTest): идут на устройстве или эмуляторе черезAndroidJUnitRunner. UI проверяется Espresso для View иcreateComposeRuleдля Compose, сценарии между приложениями через UI Automator; - интеграция с базой: Room поднимается в памяти через
Room.inMemoryDatabaseBuilder, проверяются реальные DAO и SQL, миграции схемы черезMigrationTestHelper; - интеграция с сетью: Retrofit направляется на
MockWebServerиз OkHttp, который отдаёт заготовленные ответы, включая ошибки и таймауты; - DI: в Hilt тестовый класс помечается
@HiltAndroidTest, а боевые модули подменяются через@TestInstallIn.
В CI локальные тесты идут на каждый pull request, инструментальные на эмуляторах через Gradle Managed Devices или в облачной ферме устройств. Против нестабильности помогают отключённые анимации, Android Test Orchestrator и ожидание через idling resources вместо Thread.sleep.
Добавьте пример из своего проекта: какие слои покрыты и сколько идёт прогон. Цифры называйте свои.
Где спотыкаются
Называют Retrofit и Room инструментами тестирования. Это тестируемые компоненты, а инструменты вокруг них другие: MockWebServer, база в памяти, MigrationTestHelper.
Пишут всё на Espresso. UI-тесты медленные и хрупкие, логику дешевле и надёжнее проверять локальными тестами.
Тестируют корутины с реальными диспетчерами и настоящим delay. Тест становится медленным и нестабильным, а runTest с виртуальным временем решает это без ожиданий.