- PVSM.RU - https://www.pvsm.ru -
Я участвую в развитии open source проекта Apache Ignite [1], работая над проектом мне стало интересно оценить тестовое покрытие и вот что из этого получилось.
Покрытие тестами (tests coverage) — наиболее популярная метрика используемая при оценке качества тестирования продукта.
Это одна из немногих метрик, которая позволяет выявить зоны требующие внимания из-за риска пропуска ошибки, а также выполнить приоритизацию работ по модулям или компонентам проекта.
Наиболее простой способ получить полный отчет по оценке тестового покрытия Java [2] проекта — это использовать coverage runner, встроенный в IntelliJ IDEA [3]. Он позволяет в пару кликов настроить сбор метрик и запустить тесты с последующей генерацией отчета.
В проекте Apache Ignite [1] для тестирования используется собственный тестовый фреймворк, реализованный на базе JUnit 3. На момент написания статьи core модуль проекта содержит ~82 тысячи тестов, большинство из которых являются компонентными и требуют поднятия кластера из нескольких узлов, в том числе в разных JVM, с сопутствующей подготовкой окружения.
Стоит отметить, что обеспечение работоспособности столь огромной регрессионной базы — непростая задача. Сообщество постоянно следит за состоянием продукта и исправляет найденные ошибки в рамках инициативы "Make Teamcity Green Again [4]".
Обозначенные особенности проекта не позволяют прогнать все тесты разом в одной JVM по следующим причинам:
Всё это делает невозможным использование IntelliJ IDEA [3] для получения отчета по всем тестам проекта и требует применения специального подхода к решению задачи.
Основываясь на проделанной работе, был выбран наиболее надежный подход для выполнения задачи, содержащий следующие шаги:
Существует множество инструментов предназначенных для оценки тестового покрытия, наиболее популярные из них:
Не буду останавливаться на их различиях, наглядная таблица сравнения возможностей инструментов для оценки тестового покрытия представлена здесь [8].
Для решения задачи была выбрана библиотека JaCoCo [5], для того, чтобы иметь возможность встроить решение на TeamCity [9], на которой базируется существующая инфраструктура тестирования проекта Apache Ignite [1]. TeamCity [9] умеет "из коробки" работать с JaCoCo [5].
Для автоматизации описанного алгоритма использовались bash-скрипт и Maven [10]. Конфигурация Jacoco Maven плагина [11] реализована отдельным Maven [10] профилем в pom.xml.
Профиль конфигурации JaCoCo [5] плагина приведен ниже и подразумевает разделение на 2 отдельных запуска:
<profile>
<id>coverage</id>
<properties>
<argLine>
-ea
-server
-Xms1g
-Xmx6g
-XX:+HeapDumpOnOutOfMemoryError
-XX:+AggressiveOpts
-DIGNITE_UPDATE_NOTIFIER=false
-DIGNITE_NO_DISCO_ORDER=true
-DIGNITE_PERFORMANCE_SUGGESTIONS_DISABLED=true
-DIGNITE_QUIET=false
-Djava.net.preferIPv4Stack=true
</argLine>
<coverage.dataFile>${runDirectory}/coverage-reports/jacoco-ut.exec</coverage.dataFile>
<coverage.outputDir>${runDirectory}/jacoco-ut</coverage.outputDir>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
</configuration>
<executions>
<execution>
<id>default-test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.1</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${coverage.dataFile}</destFile>
</configuration>
</execution>
<execution>
<id>post-merge</id>
<phase>validate</phase>
<goals>
<goal>merge</goal>
</goals>
<configuration>
<fileSets>
<fileSet>
<directory>${basedir}</directory>
<includes>
<include>results/*/coverage-reports/jacoco-ut.exec</include>
</includes>
</fileSet>
</fileSets>
<destFile>merged.exe</destFile>
</configuration>
</execution>
<execution>
<id>generate-report</id>
<phase>validate</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${basedir}/merged.exe</dataFile>
<outputDirectory>${basedir}/coverage-report</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
Ниже приведен скрипт реализующий описанные ранее шаги.
#!/bin/bash
# Проект должен быть скомпилирован в соответствии с DEVNOTES.txt
#
# Скрипт необходимо запускать в: ignite/modules/core
#
# Команда запуска скрипта: 'nohup ./coverage.sh >/dev/null 2>&1 &'
SCRIPT_DIR=$(cd $(dirname "$0"); pwd)
echo "***** Старт."
echo "***** Поиск тестовых классов..."
tests=()
while IFS= read -r -d $''; do
tests+=("$REPLY")
done < <(find $SCRIPT_DIR/src/test/java/org/apache/ignite -type f -name "*Test*" ! -name "*$*" ! -name "*Abstract*" ! -name "*TestSuite*" -print0)
testsCount=${#tests[@]}
echo "***** Количество тестовых классов="$testsCount
idx=0
for path in ${tests[@]}
do
idx=$((idx+1))
echo "***** Запуск "$idx" из "$testsCount
echo "***** Расположение класса: "$path
filename=$(basename -- "$path")
filename="${filename%.*}"
echo "***** Название класса: "$filename
runDir=$SCRIPT_DIR"/results/"$filename
mkdir -p $runDir
if [ "$(ls -A $runDir)" ]; then
continue
fi
echo "***** Запуск тестов..."
timeout 30m mvn -P surefire-fork-count-1,coverage test -Dmaven.main.skip=true -Dmaven.test.failure.ignore=true -Dtest=$filename -DfailIFNoTests=false -DrunDirectory=$runDir
echo "***** Очистка окружения..."
pkill java
done
# Объединение результатов и генерация отчета
mvn -X -P surefire-fork-count-1,coverage validate
echo "***** Финиш."
Прогон всех тестов с оценкой покрытия занял ~50 часов на выделенном сервере: 4 vCPU, 8RAM, 50 SSD, Ubuntu x64 16.04 [15].
Описанный подход легко может быть распараллелен на несколько стендов, при наличии ресурсов, что существенно сократит время прогона и получения оценки тестового покрытия. После встраивания данного решения на TeamCity [9] время оценки тестового покрытия должно занимать около 2-х часов.
По результатам отчета, покрытие инструкций [16] проекта составляет ~61%.
Покрытие инструкций основных компонентов:
После анализа результатов стало очевидно, что покрыт весь горячий код, а также код по исправлению типовых проблем. Имея такой инструментарий можно будет расширять покрытие на редкие и нетипичные ситуации, делая продукт еще надежнее.
P.S. Полный отчет [17] для ревизии [18].
Автор: daradurvs
Источник [19]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/maven/282301
Ссылки в тексте:
[1] Apache Ignite: https://ignite.apache.org/
[2] Java: https://java.com
[3] IntelliJ IDEA: https://www.jetbrains.com/idea/
[4] Make Teamcity Green Again: https://cwiki.apache.org/confluence/display/IGNITE/Make+Teamcity+Green+Again
[5] JaCoCo: https://github.com/jacoco/jacoco
[6] Cobertura: https://github.com/cobertura/cobertura
[7] Clover: https://bitbucket.org/atlassian/clover
[8] здесь: https://confluence.atlassian.com/clover/comparison-of-code-coverage-tools-681706101.html
[9] TeamCity: https://www.jetbrains.com/teamcity/
[10] Maven: https://maven.apache.org/
[11] Jacoco Maven плагина: https://www.eclemma.org/jacoco/trunk/doc/maven.html
[12] prepare-agent: https://www.eclemma.org/jacoco/trunk/doc/prepare-agent-mojo.html
[13] merge: https://www.eclemma.org/jacoco/trunk/doc/merge-mojo.html
[14] report: https://www.eclemma.org/jacoco/trunk/doc/report-mojo.html
[15] Ubuntu x64 16.04: http://releases.ubuntu.com/16.04/
[16] покрытие инструкций: https://www.eclemma.org/jacoco/trunk/doc/counters.html
[17] Полный отчет: https://www.dropbox.com/s/rdgs1svvojm757x/ignite-2.5-core-module-tests-coverage-report-rev-d83f1ec.zip?dl=0
[18] ревизии: https://github.com/apache/ignite/tree/d83f1ec0a4d010e57fecc12ffd3d1f8346ded61c
[19] Источник: https://habr.com/post/413587/?utm_campaign=413587
Нажмите здесь для печати.