← Назад к вопросам

Как считали покрытие Unit-тестами на проекте

1.0 Junior🔥 181 комментариев
#Soft Skills и карьера#Другое#Тестирование

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как считали покрытие Unit-тестами на проекте

Покрытие кода тестами (code coverage) — это ключевая метрика качества тестирования. На практике, каждый проект устанавливает минимальный процент покрытия (обычно 70-90%) и контролирует его. Расскажу, как я считал покрытие на своих проектах.

1. Инструменты для расчёта покрытия в Java

JaCoCo (Java Code Coverage) — самый популярный инструмент в Java экосистеме. Он интегрируется с Maven и Gradle и генерирует детальные отчёты.

Другие инструменты:

  • Cobertura — старый, но стабильный
  • Clover — коммерческий
  • OpenClover — open-source версия Clover
  • PiTest (Pitest) — для анализа мутационного тестирования

На своих проектах я использовал JaCoCo как основной, и иногда PiTest для более глубокого анализа качества.

2. Интеграция JaCoCo с Maven

Добавляю в pom.xml:

<build>
    <plugins>
        <plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <version>0.8.8</version>
            <executions>
                <execution>
                    <goals>
                        <goal>prepare-agent</goal>
                    </goals>
                </execution>
                <execution>
                    <id>report</id>
                    <phase>test</phase>
                    <goals>
                        <goal>report</goal>
                    </goals>
                </execution>
                <execution>
                    <id>jacoco-check</id>
                    <goals>
                        <goal>check</goal>
                    </goals>
                    <configuration>
                        <rules>
                            <rule>
                                <element>PACKAGE</element>
                                <excludes>
                                    <exclude>*Test</exclude>
                                </excludes>
                                <limits>
                                    <limit>
                                        <counter>LINE</counter>
                                        <value>COVEREDRATIO</value>
                                        <minimum>0.80</minimum>
                                    </limit>
                                </limits>
                            </rule>
                        </rules>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Эта конфигурация:

  • Собирает информацию о покрытии при запуске тестов
  • Генерирует HTML отчёт
  • Проверяет, что покрытие не ниже 80%

3. Запуск тестов с JaCoCo

mvn clean test

Отчёт будет в: target/site/jacoco/index.html

Открываю его в браузере и вижу:

  • Общий процент покрытия
  • Покрытие по пакетам
  • Покрытие по классам
  • Какие строки не покрыты (помечены красным)

4. Интеграция JaCoCo с Gradle

Добавляю в build.gradle:

plugins {
    id 'jacoco'
}

tasks.register('jacocoTestReport', JacocoReport) {
    dependsOn test
    
    reports {
        xml.required = true
        html.required = true
    }
}

jacocoTestCoverageVerification {
    violationRules {
        rule {
            element = 'PACKAGE'
            excludes = ['*Test']
            
            limit {
                counter = 'LINE'
                value = 'COVEREDRATIO'
                minimum = 0.80
            }
        }
    }
}

Запуск:

./gradlew test jacocoTestReport

Отчёт: build/reports/jacoco/test/html/index.html

5. Метрики покрытия

JaCoCo считает несколько типов покрытия:

МетрикаОписаниеВажность
Line CoverageПроцент строк кода, выполненных тестамиВысокая
Branch CoverageПроцент веток (if/else, switch)Высокая
Method CoverageПроцент методов, вызванных тестамиСредняя
Class CoverageПроцент классов с хотя бы одним тестомНизкая
Cyclomatic ComplexityСложность кодаСредняя

6. Пример расчёта покрытия на реальном классе

public class OrderService {
    public boolean processOrder(Order order) {
        if (order == null) {  // Line 1: Покрыто, Branch 1
            throw new IllegalArgumentException("Order is null");  // Line 2: Не покрыто
        }
        
        if (order.getAmount() <= 0) {  // Line 3: Покрыто, Branch 2
            return false;  // Line 4: Покрыто
        }
        
        order.setStatus("PROCESSING");  // Line 5: Покрыто
        return true;  // Line 6: Покрыто
    }
}

Тесты:

public class OrderServiceTest {
    
    @Test
    void testProcessValidOrder() {
        OrderService service = new OrderService();
        Order order = new Order(100.0);
        
        assertTrue(service.processOrder(order));
        // Покрыли: Lines 1, 3, 4 (if (order == null) — false branch), 5, 6
        // Branches: branch 1 (false), branch 2 (false)
    }
    
    @Test
    void testProcessOrderWithZeroAmount() {
        OrderService service = new OrderService();
        Order order = new Order(0.0);
        
        assertFalse(service.processOrder(order));
        // Покрыли: Line 3 (true branch), Line 4
        // Branch 2: true branch
    }
}

Результат:

  • Line Coverage: 5/6 = 83% (не покрыта строка 2)
  • Branch Coverage: 3/4 = 75% (не покрыта ветка if (order == null) == true)

Чтобы получить 100%, нужен ещё тест:

@Test
void testProcessNullOrder() {
    OrderService service = new OrderService();
    
    assertThrows(IllegalArgumentException.class, () -> service.processOrder(null));
}

Теперь все строки и ветки покрыты.

7. CI/CD интеграция

На GitHub Actions проверяю покрытие в каждом PR:

name: Test Coverage
on: [push, pull_request]
jobs:
  coverage:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-java@v2
        with:
          java-version: 17
      - run: mvn clean test
      - uses: codecov/codecov-action@v2
        with:
          files: ./target/site/jacoco/jacoco.xml
          fail_ci_if_error: true
          minimum_coverage: 80

Если покрытие упадёт ниже 80%, CI падает и PR не мержится.

8. Инструменты для визуализации

Codecov — облачный сервис для отслеживания покрытия:

# Загрузка отчёта на codecov.io
curl -Os https://uploader.codecov.io/latest/linux/codecov
chmod +x codecov
./codecov -f ./target/site/jacoco/jacoco.xml

Далее на codecov.io вижу:

  • Графики покрытия по времени
  • Сравнение покрытия между коммитами
  • Какие новые строки кода не покрыты
  • Статус значка (badge) для README

SonarQube — ещё один популярный инструмент:

mvn clean test sonar:sonar \
  -Dsonar.projectKey=my-app \
  -Dsonar.host.url=http://localhost:9000 \
  -Dsonar.login=mytoken

9. Практический опыт: стандарты покрытия

На разных проектах я использовал разные стандарты:

  • Core domain/business logic: 90%+ (критично)
  • Services/Use cases: 85%+ (важно)
  • Controllers/REST endpoints: 70%+ (средне)
  • Utils/Helpers: 80%+ (важно)
  • Configuration: 0% (не тестируем)
  • Entities/POJO: 50%+ (getters/setters)

10. Когда НЕ нужно 100% покрытие

Исключаю из расчёта:

  • Generated code (Lombok, Protocol Buffers)
  • Configuration классы
  • Exception constructors
  • Getters/setters простых POJO
  • Code that's impossible to test (например, catch блоки со специфическими condition)

Конфигурация для исключений в JaCoCo:

<exclude>**/config/**</exclude>
<exclude>**/entity/**</exclude>
<exclude>**/*Exception.java</exclude>

11. Мутационное тестирование (PiTest)

Для более глубокого анализа качества тестов использую PiTest:

<plugin>
    <groupId>org.pitest</groupId>
    <artifactId>pitest-maven</artifactId>
    <version>1.14.0</version>
    <configuration>
        <targetClasses>
            <param>com.myapp.service.*</param>
        </targetClasses>
        <targetTests>
            <param>com.myapp.service.*Test</param>
        </targetTests>
    </configuration>
</plugin>

Запуск:

mvn org.pitest:pitest-maven:mutationCoverage

ПиTest может обнаружить тесты, которые не проверяют корректность поведения (например, тесты, которые проходят даже если изменить логику).

Вывод

На практике я:

  1. Использовал JaCoCo как основной инструмент
  2. Установил минимум 80% покрытия для критических компонентов
  3. Интегрировал в CI/CD для автоматического контроля
  4. Использовал Codecov для мониторинга тренда
  5. Иногда применял PiTest для глубокого анализа
  6. Исключал некритичный код (config, entities) из расчётов
  7. Фокусировался на качестве тестов, а не на проценте покрытия

Главное правило: покрытие 100% не гарантирует качество кода, но покрытие 70%+ помогает избежать очевидных ошибок.