Difference between revisions of "Sonar + maven configuration + Jenkins"

Line 50: Line 50:
 
         <!-- ==== SONARQUBE quality metrics ==== -->
 
         <!-- ==== SONARQUBE quality metrics ==== -->
 
         <maven.jacoco.version>0.7.4.201502262128</maven.jacoco.version>
 
         <maven.jacoco.version>0.7.4.201502262128</maven.jacoco.version>
        <maven.sonar-jacoco-listeners.version>3.2</maven.sonar-jacoco-listeners.version>
 
 
         <!-- Global Sonar settings. Do not change them! -->
 
         <!-- Global Sonar settings. Do not change them! -->
 
         <sonar.language>java</sonar.language>
 
         <sonar.language>java</sonar.language>
Line 65: Line 64:
 
         <!--            ${session.executionRootDirectory} = directory from where the "mvn" command is run -->
 
         <!--            ${session.executionRootDirectory} = directory from where the "mvn" command is run -->
 
         <!-- a) Where sonar will find the standard test reports -->
 
         <!-- a) Where sonar will find the standard test reports -->
         <sonar.junit.reportsPath>${project.build.directory}/surefire-reports</sonar.junit.reportsPath>
+
         <sonar.surefire.reportsPath>${project.build.directory}/surefire-reports</sonar.surefire.reportsPath>
         <sonar.junit.itReportsPath>${session.executionRootDirectory}/target/failsafe-reports</sonar.junit.itReportsPath>
+
         <sonar.failsafe.reportsPath>${session.executionRootDirectory}/target/failsafe-reports</sonar.failsafe.reportsPath>
 
         <!-- b) Sonar specific reports -->
 
         <!-- b) Sonar specific reports -->
         <sonar.out.unitTestsReport>${project.build.directory}/jacoco-ut.exec</sonar.out.unitTestsReport>
+
         <sonar.jacoco.reportPath>${project.build.directory}/jacoco-unit.exec</sonar.jacoco.reportPath>
         <sonar.out.integrationTestsReport>${session.executionRootDirectory}/target/reports/jacoco-it.exec</sonar.out.integrationTestsReport>
+
         <sonar.jacoco.itReportPath>${session.executionRootDirectory}/target/reports/jacoco-it.exec</sonar.jacoco.itReportPath>
 
     </properties>
 
     </properties>
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
  
  
 
=Jacoco plugin (coverage agent)=
 
=Jacoco plugin (coverage agent)=
  
 +
This is how you should configure this plugin:
 +
 +
<syntaxhighlight lang="xml">
 +
            <!-- == Jacoco agent configuration == -->
 +
            <!-- This will auto-generate the right jacoco command for Unit | Integration tests -->
 +
            <plugin>
 +
                <groupId>org.jacoco</groupId>
 +
                <artifactId>jacoco-maven-plugin</artifactId>
 +
                <version>${maven.jacoco.version}</version>
 +
                <executions>
 +
                    <!-- Unit tests configuration -->
 +
                    <execution>
 +
                        <id>prepare-unit-test-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>
 +
                    <!-- Integration tests configuration -->
 +
                    <execution>
 +
                        <id>prepare-integration-test-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>
 +
</syntaxhighlight>
 +
 +
 +
This will defined 2 properties, depending on the maven phase:
  
 +
{| class="wikitable"
 +
|-
 +
! Header text !! Header text !! Header text
 +
|-
 +
|  || Phase || ArgLine || Value
 +
|-
 +
| Unit Tests || process-test-classes || jacoco.agent.ut.arg || -javaagent:${jacoco.lib.path}=destFile=${sonar.jacoco.'''reportPath'''},append=true
 +
|-
 +
| Integration Tests || pre-integration-test || jacoco.agent.it.arg || -javaagent:${jacoco.lib.path}=destFile=${sonar.jacoco.'''itReportPath'''},append=true
 +
|}
  
 +
These properties will be re-use in the corresponding maven plugin.
  
  

Revision as of 15:51, 20 May 2015


SonarQube requires quite some configuration to be fully useful!

This article explains how to configure your maven projects to use SonarQube properly, bringing both Unit and Integration tests coverage.


Principle

To work well SonarQube requires 4 configuration steps:

TODO: nice picture


Key points:

  • SONAR is configured for JAVA language and it will use Jacoco as coverage tool.
  • Each maven module will have its own Unit Tests results (Surefire reports + .exec file) inside its own target directory
  • The Integration Tests results are common. Meaning, all modules will write in the same directory. That directory is relative to the maven execution.


Sonar properties

First of all you need to configure SONAR by setting up some properties and paths.

Technical details:

  • Surefire unit tests plugin
    • Outputs in ${project.build.directory}
    • 1 XML file per test class in: ${sonar.junit.reportsPath}
    • SONAR report file (jacoco-ut.exec) will be available at ${sonar.out.unitTestsReport}
  • Failsafe integration tests plugin
    • All outputs in the same directory, relative to the local execution: ${session.executionRootDirectory}


POM.xml extract:

    <properties>
        ...

        <!-- Maven plugins -->
        <maven-surefire-plugin.version>2.18.1</maven-surefire-plugin.version>
        <maven-failsafe-plugin.version>2.18.1</maven-failsafe-plugin.version>
 
        <!-- Test frameworks -->
        <junit.version>4.12</junit.version>
 
        <!-- ==== SONARQUBE quality metrics ==== -->
        <maven.jacoco.version>0.7.4.201502262128</maven.jacoco.version>
        <!-- Global Sonar settings. Do not change them! -->
        <sonar.language>java</sonar.language>
        <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
        <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
        <jacoco.lib.path>
            ${settings.localRepository}/org/jacoco/org.jacoco.agent/${maven.jacoco.version}/org.jacoco.agent-${maven.jacoco.version}-runtime.jar
        </jacoco.lib.path>
        <javaagent>${jacoco.lib.path}</javaagent>
        <!-- Don't let Sonar execute tests. We will let Maven do it during build phase -->
        <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
        <!-- Report -->
        <!-- IMPORTANT: integration test path must be ABSOLUTE, especially for muli-modules projects -->
        <!--            ${session.executionRootDirectory} = directory from where the "mvn" command is run -->
        <!-- a) Where sonar will find the standard test reports -->
        <sonar.surefire.reportsPath>${project.build.directory}/surefire-reports</sonar.surefire.reportsPath>
        <sonar.failsafe.reportsPath>${session.executionRootDirectory}/target/failsafe-reports</sonar.failsafe.reportsPath>
        <!-- b) Sonar specific reports -->
        <sonar.jacoco.reportPath>${project.build.directory}/jacoco-unit.exec</sonar.jacoco.reportPath>
        <sonar.jacoco.itReportPath>${session.executionRootDirectory}/target/reports/jacoco-it.exec</sonar.jacoco.itReportPath>
    </properties>


Jacoco plugin (coverage agent)

This is how you should configure this plugin:

            <!-- == Jacoco agent configuration == -->
            <!-- This will auto-generate the right jacoco command for Unit | Integration tests -->
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>${maven.jacoco.version}</version>
                <executions> 
                    <!-- Unit tests configuration -->
                    <execution>
                        <id>prepare-unit-test-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>
                    <!-- Integration tests configuration -->
                    <execution>
                        <id>prepare-integration-test-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>


This will defined 2 properties, depending on the maven phase:

Header text Header text Header text
Phase ArgLine Value
Unit Tests process-test-classes jacoco.agent.ut.arg -javaagent:${jacoco.lib.path}=destFile=${sonar.jacoco.reportPath},append=true
Integration Tests pre-integration-test jacoco.agent.it.arg -javaagent:${jacoco.lib.path}=destFile=${sonar.jacoco.itReportPath},append=true

These properties will be re-use in the corresponding maven plugin.


Surefire configuration (UT tests)

Failsafe configuration (IT tests)

Real life example

You can check out one of my GitHub project:


Even better, you can check out this excellent tutorial:



References

This article is based on my daily work in VEHCO.

To update to SonarQube I used the following articles and code examples: