Было ли тестовое покрытие больше 80% на проектах
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Тестовое покрытие на проектах: подход и практика
На проектах, где я работал, целевой показатель покрытия в 80% и более действительно часто фигурировал в требованиях к качеству кода, особенно в зрелых, долгосрочных продуктах в сферах финтеха, стриминга и крупных корпоративных приложений. Однако важно понимать, что сама по себе цифра в 80% — это не самоцель, а инструмент метрики, и ее достижение было результатом продуманной стратегии, а не формального "накручивания" процентов.
Стратегия достижения высокого покрытия
Простое требование "добиться 80%" без четкой стратегии ведет к написанию бесполезных тестов. На успешных проектах мы действовали системно:
- Приоритизация по критичности и сложности. Первыми покрывались тестами:
* **Бизнес-логика ядра приложения** (расчеты, преобразования данных, состояния).
* **Модули, подверженные частым изменениям** (это страховка от регрессий).
* **Сложные алгоритмы и цепочки преобразований данных**.
* **Public API модулей и библиотек**, используемых другими командами.
-
Использование модульных (Unit) и интеграционных (Integration) тестов как основы. Именно они дают основной вклад в процент покрытия и максимальную скорость обратной связи.
// Пример юнит-теста для ViewModel с использованием Coroutines Test class UserProfileViewModelTest { @Test fun `loadUserProfile should update state to Success on repository success`() = runTest { // Arrange val mockUser = User(id = 1, name = "Test") val mockRepository = FakeUserRepository().apply { userToReturn = mockUser } val viewModel = UserProfileViewModel(mockRepository) // Act viewModel.loadUserProfile(1) // Assert val state = viewModel.uiState.first() assertThat(state).isInstanceOf(UserProfileState.Success::class.java) assertThat((state as UserProfileState.Success).user).isEqualTo(mockUser) } } -
Умное игнорирование нерелевантного кода. С помощью аннотаций в JaCoCo мы исключали из отчетов:
* Сгенерированный код (Data Binding, Dagger).
* Чисто UI-классы (Activity, Fragment, простые адаптеры), логика которых вынесена в ViewModel/Presenter.
* Модели данных (data class), состоящие только из полей и автоматических методов.
```kotlin
// Пример: логика вынесена из Fragment, что позволяет ее протестировать
// Сам Fragment можно исключить из отчетов покрытия
class CatalogViewModel @Inject constructor(
private val loadProductsUseCase: LoadProductsUseCase
) : ViewModel() {
// Эта бизнес-логика покрывается юнит-тестами
fun onCategorySelected(categoryId: String) {
viewModelScope.launch {
_state.value = State.Loading
val result = loadProductsUseCase(categoryId)
_state.value = when (result) {
is Result.Success -> State.Content(result.data)
is Result.Error -> State.Error(result.exception.message)
}
}
}
}
```
Организационные практики, которые помогали
- CI/CD как gatekeeper. В GitLab CI/CD или Jenkins этап сборки с запуском тестов и проверкой покрытия был обязательным. Падение покрытия ниже порога (например, с 82% до 78%) могло блокировать мерж пул-реквеста в основную ветку. Это дисциплинировало команду.
- Визуализация и регулярный мониторинг. Интеграция JaCoCo в процесс сборки с генерацией HTML-отчетов, которые можно было изучить. Мы проводили регулярные обзоры, выявляя непокрытые, но важные участки кода.
- Культура "тесты прежде всего" (TDD в отдельных потоках). Для ключевых фич или рефакторинга критически важных модулей мы практиковали Test-Driven Development. Это сразу давало высокое покрытие и более чистый дизайн кода.
Вывод: баланс метрики и здравого смысла
Таким образом, да, на многих проектах мы поддерживали стабильное покрытие выше 80%. Но эта цифра была следствием, а не причиной. Ключевыми были:
- Осмысленное тестирование важной логики, а не гонка за процентами.
- Автоматизированная проверка покрытия в контуре CI/CD.
- Гибкая настройка инструментов (JaCoCo) для исключения из метрик кода, который не имеет смысла тестировать юнит-тестами.
Главный урок: высокий процент покрытия — это хороший индикатор наличия тестовой культуры, но только если он достигается за счет тестирования реальной логики, а не тривиальных геттеров или автосгенерированных методов. Слепое требование "80% любой ценой" может привести к пустой трате времени и созданию хрупких, бесполезных тестов.