Unit и UI тестирование Android‑приложений — практическое руководство

Короткий ответ: сначала покрывайте логику unit‑тестами (JVM), затем добавляйте UI‑тесты (Espresso/Compose) и запускайте всё в CI через Gradle; для масштабного прогонов используйте Firebase Test Lab. Ниже — пошагово и применимо прямо в проекте.

Оглавление {{TOC_AUTOMATIC}}

Что такое unit‑тесты и как их писать

Unit‑тесты проверяют маленькие единицы кода (методы, классы) без запуска UI и внешних сервисов. Плюсы: быстрые, пригодны для CI, дают раннюю обратную связь.

Как начать

  • Разместите тесты в app/src/test/java.
  • Используйте JUnit 5 (аннотации @Test, @BeforeEach) + assertEquals/assertThrows.
  • Моки: Mockito или MockK (для Kotlin). Для корутин — runTest из kotlinx‑coroutines‑test.

Пример простого теста (Kotlin):

class CalculatorTest {
  @Test
  fun `calculateTotal with valid inputs returns correct sum`() {
    val calc = Calculator()
    val result = calc.calculateTotal(100.0, 0.2)
    assertEquals(120.0, result, 0.001)
  }
}

Покрытие и метрики

  • Подключите JaCoCo: цель 70–90% для unit.
  • Запускайте тесты локально и в CI (./gradlew testDebugUnitTest).
  • Пишите тесты на граничные случаи: нули, отрицательные значения, null (если применимо).

Запускайте unit‑тесты перед коммитом — это экономит время на отладку и снижает вероятность регрессий.

UI‑тесты: Espresso, Compose Testing и окружение

UI‑тесты эмулируют действия пользователя: ввод, клики, навигацию. Они медленнее, но проверяют интеграцию экранов и поведение на устройстве.

Выбор инструмента

  • Espresso — для классического View‑UI, надёжный для черного ящика.
  • Compose Testing — если UI на Jetpack Compose; быстрый и позволяющий проверять семантику.
  • UI Automator — для взаимодействия между приложениями или системных диалогов.

Где писать и запускать

  • Код тестов: app/src/androidTest/java.
  • Запуск: ./gradlew connectedAndroidTest для локальных девайсов/эмуляторов.
  • Для CI/облачных прогонов: интеграция с Firebase Test Lab (runInstrumentationTests).

Примеры сценариев

  • Логин: неверный пароль, повторные попытки, сохранение сессии.
  • Навигация: правильная back‑логика и стейт при смене конфигурации.
  • Edge: потеря сети, медленные ответы, orientation change.

Не игнорируйте flaky‑тесты: фиксация сидов, стабилизация таймаутов и минимизация зависимости от внешних сервисов критичны.

Инструменты и интеграция в CI/CD

Рекомендации по инструментам

  • Unit: JUnit 5, Mockito/MockK, Kotest (для BDD/Kotlin‑нативных тестов).
  • UI: Espresso, Compose Testing, UI Automator.
  • Покрытие: JaCoCo.
  • Облачное тестирование: Firebase Test Lab (множество устройств и API‑уровней).

Пример задач Gradle для CI

  • Unit: ./gradlew testDebugUnitTest
  • UI на подключённом устройстве: ./gradlew connectedAndroidTest
  • Сбор покрытия: ./gradlew jacocoTestReport

CI‑стратегия

  • Unit на каждом PR (быстро).
  • UI: nightly или per‑release; критичные UI‑тесты можно запускать в PR, но экономичнее — smoke‑набор.
  • Используйте матрицу устройств в CI/Firebase: Android API, экраны, density.

Частые ошибки

  • Тестирование приватных методов — обычно лишнее; тестируйте поведение, не реализацию.
  • Статические зависимости и глобальные синглтоны в коде — усложняют моки. Инвертируйте зависимости.
  • Игнорирование многопоточности: для корутин используйте runTest и TestDispatcher.
  • Ожидания по времени вместо явных синхронизаций в UI (используйте Idling Resources или composeTestRule.waitForIdle()).
  • Недостаток стабильного тестового окружения — держите фиктивные ответы, локальные фейковые репозитории.

FAQ

  • Какой порядок тестирования? Начните с unit, затем интеграционные и UI — это дает лучшее соотношение усилий к результату.
  • Нужно ли 100% покрытие? Нет. Цель — покрытие критичных участков: бизнес‑логика и критичные сценарии; 70–90% по unit и 50%+ по UI — разумно.
  • Как уменьшить flaky‑тесты? Зафиксируйте random seed, уберите внешние зависимости, используйте стабильные тестовые данные и idling mechanisms.

С такими практиками вы получите стабильные сборки и предсказуемые релизы: инвестируйте сначала в unit‑тесты (80% уверенности за 20% усилий), затем автоматизируйте UI‑прогоны и CI.