Статьи

Интеграция Jenkins, JaCoCo и SonarQube с Maven

Использование Jenkins для создания вашего приложения, запуск тестов с покрытием кода Jacoco, анализ SonarQube и сохранение всех результатов в SonarQube онлайн — отличный способ развертывания ваших приложений. 

В этой статье вы сможете использовать Jenkins с Maven и управлять следующими задачами:

  • Построить приложение 

  • Выполнение тестов с отчетом о тестировании Jacoco

  • Выполнение анализа SonarQube

  • Передача результатов теста, отчета о покрытии теста и отчета об анализе SonarQube на сервер SonarQube.

Другие общие задачи, такие как извлечение исходных кодов из системы контроля версий или развертывание войны на сервере приложений, выходят за рамки этой статьи.

Дженкинс

Jenkins — это отмеченное наградами кроссплатформенное приложение для непрерывной интеграции и непрерывной доставки. Используйте Jenkins для  непрерывной сборки и тестирования своих программных проектов,  что облегчает разработчикам интеграцию изменений в проект и облегчает пользователям получение новой сборки. Он также позволяет вам  непрерывно поставлять  программное обеспечение, предоставляя мощные способы определения конвейеров сборки и интегрируя с большим количеством технологий тестирования и развертывания.

Сначала вам нужен экземпляр Дженкинса. Если у вас уже есть, вы можете использовать его. Вы можете скачать последнюю версию с  https://jenkins-ci.org/

Дженкинс Сонар Плагин

Установите Jenkins «SonarQube Plugin» с Центром обновлений (не Sonargraph). URL плагина: 

https://wiki.jenkins-ci.org/display/JENKINS/SonarQube+plugin 

SonarQube

SonarQube — это открытая платформа для управления качеством кода. Таким образом, он охватывает 7 осей: дублированный код, стандарты кодирования, модульные тесты, сложный код, потенциальные ошибки, комментарии, дизайн и архитектура.

Если у вас нет экземпляра SonarQube, вам необходимо установить его с  http://www.sonarqube.org/

Конфигурация сервера SonarQube в Дженкинс

Чтобы добавить новый сервер SonarQube, выполните «Управление Jenkins -> Настройка системы» и найдите опцию «Добавить Sonar». Под ссылкой «Дополнительно» заполните свойства сервера:

Name: MySonarServer
Server URL: http://10.210.99.88:9000
Sonar account login: sonar
Sonar account password: myPass
Database URL: jdbc:mysql://10.210.99.88:3306/sonar?useUnicode=true&characterEncoding=utf8
Database login: sonar
Database password: myDbPass
Database driver: com.mysql.jdbc.Driver

Опция покрытия для сценария сборки 

Добавьте опцию maven сборки «verify -Prun-its, охват», чтобы получить отчет о тестировании покрытия. Пример:

Неудачное тестовое поведение

У Maven есть параметр, чтобы остановить или продолжить после неудачных тестов. В идеальном случае, если тесты не пройдены, лучше остановить сборку. В Jenkins вы можете установить эту опцию с помощью «Build-> Advanced-> MAVEN_OPTS» и добавить следующий параметр.

-Dmaven.test.failure.ignore=true

Добавление SonarQube в Jenkins Post-Build

Вы можете добавить анализ Sonar в Jenkins с помощью опции «Добавить действия после сборки». Это список, поэтому, если существует более одной установки Sonar, выберите тот, который вы добавили.

Обновления ПОМ

Внутри тега <properties> добавьте свойства проекта SonarQube. Если вы не установите какое-либо свойство, SonarQube будет использовать значение по умолчанию.

<!--  This format is used by SonarQube. If you need another format see "buildnumber-maven-plugin" -->
<maven.build.timestamp.format>MM.yyyy</maven.build.timestamp.format>
<yearMonth>${maven.build.timestamp}</yearMonth>    
<!-- ************************-->
<!-- Sonar/Reporting settings -->
<!-- ************************-->
<!-- Sonar/Jacoco integration. Note that these properties need to be defined outside the "coverage" profile
because we want to be to able to execute mvn sonar:sonar without passing a profile -->
<!-- Tells Sonar to use jacoco for coverage results -->
<sonar.projectKey>MyProjectKey</sonar.projectKey>
<sonar.projectName>My Project</sonar.projectName>
 <sonar.projectVersion>${yearMonth}</sonar.projectVersion>
<sonar.language>java</sonar.language>
<sonar.sourceEncoding>UTF-8</sonar.sourceEncoding>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<!-- Jacoco version to use -->
<jacoco.version>0.7.2.201409121644</jacoco.version>
<!-- The Sonar Jacoco Listener for JUnit to extract coverage details per test -->
<sonar-jacoco-listeners.version>1.4</sonar-jacoco-listeners.version>
<!-- Don't let Sonar execute tests. We will ask it to Maven 'sonar.dynamicAnalysis' is deprecated since version 4.3 and should no longer be used. -->
<!-- <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis> -->
<!-- The system property jacoco.outputDir needs to be override on the command line
    with an absolute path if you want to merge results from all modules.
    Example in a Jenkisn build where ${WORKSPACE} is defined and your project in the root directory of the workspace :
    mvn clean install -Prun-its,coverage -Djacoco.outputDir=${WORKSPACE}/target
    Note that unfortunately using the following does not work because of
    http://jira.codehaus.org/browse/SONAR-3427:
<jacoco.outputDir>${session.executionRootDirectory}/target/</jacoco.outputDir>
-->
<jacoco.outputDir>${project.build.directory}</jacoco.outputDir>
<!-- Jacoco output file for UTs -->
<jacoco.out.ut.file>jacoco-ut.exec</jacoco.out.ut.file>
<!-- Tells Sonar where the Jacoco coverage result file is located for Unit Tests -->
<sonar.jacoco.reportPath>${jacoco.outputDir}/${jacoco.out.ut.file}</sonar.jacoco.reportPath>
<!-- Jacoco output file for ITs -->
<jacoco.out.it.file>jacoco-it.exec</jacoco.out.it.file>
<!-- Tells Sonar where the Jacoco coverage result file is located for Integration Tests -->
<sonar.jacoco.itReportPath>${jacoco.outputDir}/${jacoco.out.it.file}</sonar.jacoco.itReportPath>
<!-- <sonar.junit.reportsPath>${project.build.directory}/surefire-reports/</sonar.junit.reportsPath> -->
<!-- <sonar.tests>src/test/java</sonar.tests> -->
<!-- === END of Sonar/Reporting settings === -->

Для покрытия кода Jacoco добавьте следующий код в тег профиля

<!-- coverage -->
<profile>
    <id>coverage</id>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <argLine>${jacoco.agent.ut.arg}</argLine>
                    <!-- Specific to generate mapping between tests and covered code -->
                    <properties>
                        <property>
                            <name>listener</name>
                            <value>org.sonar.java.jacoco.JUnitListener</value>
                        </property>
                    </properties>
                    <!-- test failure ignore -->
                    <testFailureIgnore>true</testFailureIgnore>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
                <configuration>
                    <argLine>-Xmx1024m -XX:MaxPermSize=256m ${jacoco.agent.it.arg}
                    </argLine>
                    <!-- Specific to generate mapping between tests and covered code -->
                    <properties>
                        <property>
                            <name>listener</name>
                            <value>org.sonar.java.jacoco.JUnitListener</value>
                        </property>
                    </properties>
                    <!-- Let's put failsafe reports with surefire to have access to tests 
                        failures/success reports in sonar -->
                    <reportsDirectory>${project.build.directory}/surefire-reports
                    </reportsDirectory>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>${jacoco.version}</version>
                <executions>
                    <!-- Prepares a variable, jacoco.agent.ut.arg, that contains the info 
                        to be passed to the JVM hosting the code being tested. -->
                    <execution>
                        <id>prepare-ut-agent</id>
                        <phase>process-test-classes</phase>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                        <configuration>
                            <destFile>${sonar.jacoco.reportPath}</destFile>
                            <propertyName>jacoco.agent.ut.arg</propertyName>
                            <append>true</append>
                        </configuration>
                    </execution>
                    <!-- Prepares a variable, jacoco.agent.it.arg, that contains the info 
                        to be passed to the JVM hosting the code being tested. -->
                    <execution>
                        <id>prepare-it-agent</id>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                        <configuration>
                            <destFile>${sonar.jacoco.itReportPath}</destFile>
                            <propertyName>jacoco.agent.it.arg</propertyName>
                            <append>true</append>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.codehaus.sonar-plugins.java</groupId>
            <artifactId>sonar-jacoco-listeners</artifactId>
            <version>${sonar-jacoco-listeners.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</profile>
<!-- Integraton tests -->
<profile>
    <id>run-its</id>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
                <executions>
                    <execution>
                        <id>integration-test</id>
                        <phase>integration-test</phase>
                        <goals>
                            <goal>integration-test</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>verify</id>
                        <phase>verify</phase>
                        <goals>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>

Выполнив все эти шаги, вы сможете запустить анализ SonarQube для каждого развертывания. Кроме того, вы увидите отчет о тестировании и покрытие кода тестирования на странице проекта SonarQube.

Вы можете увидеть скриншоты результата:

Отчет об испытаниях агрегатов Jenkins

Сводка испытаний и покрытий

Отчет о модульных испытаниях

Отчет о покрытии модульных испытаний