Где пишутся юнит-тесты
Что проверяют
Знаете ли вы, как устроен тестовый контур Android-проекта: где лежат тесты, на чём они запускаются и чем локальный тест отличается от инструментального. Следом обычно спрашивают, как протестировать ViewModel с корутинами или код, который обращается к Android SDK.
Как отвечать
В модуле Gradle два тестовых source set:
src/test/java(илиsrc/test/kotlin): локальные юнит-тесты. Запускаются на JVM вашей машины или CI без эмулятора, за секунды. Зависимости черезtestImplementation, запуск./gradlew testDebugUnitTest;src/androidTest/: инструментальные тесты, выполняются на устройстве или эмуляторе. Здесь Espresso, UI-тесты Compose, проверки Room на настоящем SQLite. Зависимости черезandroidTestImplementation, запуск./gradlew connectedDebugAndroidTest.
Юнит-тесты пишут в src/test на то, что не зависит от фреймворка: ViewModel, use case, репозитории, мапперы, валидацию. Типичный набор: JUnit 4 (JUnit 5 на Android подключают отдельным плагином), MockK или Mockito для моков, kotlinx-coroutines-test с runTest и тестовым диспетчером через Dispatchers.setMain, Turbine для проверки Flow.
Когда код всё же касается Android-классов, в src/test помогает Robolectric: он подменяет фреймворк на JVM, и часть тестов, которым раньше нужен был эмулятор, становится локальной. Для ресурсов включают testOptions.unitTests.isIncludeAndroidResources = true.
Архитектура здесь видна сразу: чем меньше Context и android.* в бизнес-логике, тем больше тестов живёт в быстром src/test.
Где спотыкаются
Называют только src/test и не знают про androidTest, либо наоборот кладут в androidTest всё подряд и ждут эмулятор ради проверки маппера.
Вызывают в локальном тесте, например, Log.d или TextUtils и получают RuntimeException «Method ... not mocked»: в src/test подключён android.jar без реализаций. Правильный выход: вынести зависимость за интерфейс или взять Robolectric, а не глушить ошибку через isReturnDefaultValues.
Тестируют корутины без runTest и тестового диспетчера, из-за чего тесты то проходят, то падают, или ждут настоящие задержки вместо виртуального времени.