name: testing description: Пиши тесты в андроид-проекте правильно. Используй этот навык при написании любых типов тестов (unit, integration, UI), тестировании бизнес-логики, сетевых функций и компонентов UI.
Тестирование
When to Use
- Используй этот навык, когда пишешь unit-тесты для бизнес-логики (ViewModels, Use Cases, Domain models)
- Используй этот навык, когда пишешь интеграционные тесты для DAO и Repository
- Используй этот навык, когда пишешь UI тесты для Compose компонентов
- Используй этот навык, когда тестируешь сетевые функции (только на моках)
- Используй этот навык, когда тестируешь Flow/StateFlow с использованием Turbine
- Используй этот навык, когда нужно протестировать обработку исключений в корутинах
- Этот навык полезен при выборе правильного типа теста для конкретного сценария
- Этот навык помогает определить, когда использовать unit-тесты с моками, а когда интеграционные тесты
Типы тестов
- Unit: бизнес-логика изолированно, MockK для зависимостей, AAA паттерн
- Integration: взаимодействие слоев (DAO, Repository), реальные реализации БД
- UI: критические сценарии, Compose Testing для компонентов
Инструменты
- JUnit 5 - unit-тесты
- MockK - мокирование
- Compose Testing - Compose компоненты
- Room Testing - для интеграционных тестов БД
- kotlinx-coroutines-test - для тестирования корутин
- Turbine - для тестирования Flow/StateFlow (app.cash.turbine:turbine:1.1.0)
Запуск тестов и отчеты
Команда make test
Используйте команду make test для запуска всех unit-тестов:
make test
Эта команда:
- Запускает
./gradlew test --console=plain- все unit-тесты (JVM, без устройства) - Автоматически выполняет скрипт
scripts/test_report.pyпосле завершения тестов - Показывает детальный отчет со статистикой по тестовым классам
Скрипт test_report.py
Скрипт scripts/test_report.py генерирует детальный отчет о результатах тестов:
- Показывает общую статистику: всего тестов, успешные, упавшие
- Выводит список всех упавших тестов с именами классов и методов
- Отображает таблицу статистики по тестовым классам (всего, упало, успешно)
- Сортирует классы по количеству упавших тестов (по убыванию)
- Использует цвета для удобного чтения (зеленый для успеха, красный для ошибок)
- Возвращает exit code 0 если все тесты прошли, 1 если есть упавшие
Пример вывода скрипта:
================================================================================
✅ СБОРКА УСПЕШНА
================================================================================
Статистика тестов:
Всего тестов: 145
✅ Успешные: 142
❌ Упавшие: 3
❌ Список упавших тестов:
- AuthViewModelTest::login_withInvalidCredentials_returnsError
- EventsViewModelTest::loadEvents_whenNetworkError_returnsError
- ParksRepositoryImplTest::getParks_whenEmpty_returnsEmptyList
================================================================================
Статистика по тестовым классам (5 классов):
================================================================================
Класс Упало Успешно Всего
----------------------------------------------------------------------------
AuthViewModelTest 1 12 13
EventsViewModelTest 1 8 9
ParksRepositoryImplTest 1 15 16
================================================================================
Другие команды тестирования
make android-test- запуск интеграционных тестов на Android устройствеmake test-all- запуск всех тестов (unit + интеграционные)make android-test-report- открыть HTML отчет интеграционных тестов в браузере
Структура
app/src/test/- unit-тесты (ViewModels, Use Cases, Domain models)app/src/androidTest/- integration/UI тесты (DAO, Repository, UI компоненты)- Структура зеркалит код
- Имена классов:
*Test
Best Practices
Важно: Рекомендации по интеграционным тестам ViewModels
- ✅ Рекомендуется: Тестировать ViewModels через unit-тесты с MockK в test/
- ⚠️ Возможно (но не рекомендуется): Интеграционные тесты ViewModels в androidTest/ с использованием
runTest,MainDispatcherRuleиTurbine - ✅ Допустимо: Интеграционные тесты для компонентов с Android API (например, CryptoManager с Android Keystore)
- ✅ Допустимо: UI-тесты для Compose компонентов без бизнес-логики
Почему unit-тесты с MockK предпочтительнее:
- Быстрее выполняются (не нужны реальный Repository/БД)
- Более стабильны и изолированы
- В Jetpack-WorkoutApp все ViewModels тестируются через unit-тесты (AuthViewModelTest, EventsViewModelTest)
Когда использовать интеграционные тесты ViewModels:
- Только если нужно протестировать интеграцию с реальным Repository/БД
- В JetpackWorkoutApp пока не используется, но технически возможно
Рабочий подход к тестированию
См. подробные примеры в references/EXAMPLES.md.
Unit-тесты ViewModels (с MockK)
Важно: ViewModels, использующие viewModelScope.launch, требуют MainDispatcherRule в тестах. viewModelScope работает на Dispatchers.Main, который не настроен по умолчанию в Unit-тестах. Без MainDispatcherRule корутины не смогут запуститься, и проверки состояния будут неверными.
Пример создания MainDispatcherRule: см. references/EXAMPLES.md -> "Создание MainDispatcherRule"
Интеграционные тесты DAO и Repository
Интеграционные тесты ViewModels (только для существующих)
UI-тесты Compose компонентов
Тестирование сетевых функций
- ✅ Только на моках: Использовать MockK для API клиентов (SWApi, Retrofit)
- ❌ Без реальных запросов: Запрещены реальные HTTP запросы к серверу в тестах
- ✅ Изолированное тестирование: Тестировать бизнес-логику независимо от сети
- ✅ Предсказуемые ответы: Использовать фиксированные mock-ответы от сервера
См. примеры в references/EXAMPLES.md:
Пример тестирования с моком
Мокирование HttpException
Тестирование Flow с исключениями
Важно: Для Flow с исключениями, которые обрабатываются через catch, используйте first() или collect() вместо Turbine.
См. примеры в references/EXAMPLES.md:
Тестирование IOException (обрабатывается в catch)
Тестирование других исключений (пробрасываются дальше)
Мокирование Android Log
Общие практики
- Быстрые и независимые тесты
- Описательные имена
- Один тест - одна проверка
- Тестировать поведение, не реализацию
- Интеграционные тесты только для DAO и Repository
- Unit-тесты для ViewModels с моками
- Сетевые функции только на моках (без реальных запросов)
- UI-тесты для Compose компонентов без бизнес-логики
- Использовать JUnit 5 аннотации (
@Test,@Before,@After) - Использовать assertions JUnit 5 (
assertEquals,assertTrue,assertNull)