SonarQube配置总结

SonarQube的安装很简单,这里不做赘述。主要总结一下SonarQube的一些实际应用。

SonarQube Jenkins配置

安装并配置好SonarQube后,在Jenkins插件管理中添加SonarQube Scanner for Jenkins插件,然后在Jenkins系统设置中设置SonarQube servers信息。

SonarQube Service Jenkins配置

最后在具体的项目配置中的Post Steps中添加Execute SonarQube Scanner

SonarQube项目配置

这样配置后在Jenkins上构建项目时会自动执行SonarQube代码扫描,但是由于很多时候Jenkins上Build中都配置-Dmaven.test.skip=true跳过测试,这样就统计不出测试覆盖率。

SonarQube本地化

由于Jenkins上配置扫描不出测试覆盖率,最后考虑直接在POM中配置插件,通过开发人员自己来进行代码扫描。首先需要配置sonar-maven-plugin插件,这里将插件的sonar目标绑定到Maven的default生命周期的post-integration-test阶段,是为了方便代码扫描,也可以不进行绑定直接执行mvn sonar:sonar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.6.0.1398</version>
<executions>
<execution>
<id>sonar-scan</id>
<phase>post-integration-test</phase>
<goals>
<goal>sonar</goal>
</goals>
</execution>
</executions>
</plugin>

这里使用的jacoco-maven-plugin来进行代码测试覆盖率的统计,该插件的report目标也是绑定在Maven的default生命周期的test阶段,将该插件声明在sonar-maven-plugin的前面,让其先执行覆盖率统计工作,以便sonar-maven-plugin插件使用覆盖率统报告。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.3</version>
<configuration>
<excludes>
<exclude>**/support/xml/*</exclude>
</excludes>
</configuration>
<executions>
<!--
Prepares the property pointing to the JaCoCo runtime agent which
is passed as VM argument when Maven the Surefire plugin is executed.
-->
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<!-- Sets the path to the file which contains the execution data. -->
<destFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</destFile>
<!--
Sets the name of the property containing the settings
for JaCoCo runtime agent.
-->
<propertyName>surefireArgLine</propertyName>
</configuration>
</execution>
<!--
Ensures that the code coverage report for unit tests is created after
unit tests have been run.
-->
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<!-- Sets the path to the file which contains the execution data. -->
<dataFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</dataFile>
<!-- Sets the output directory for the code coverage report. -->
<outputDirectory>${project.reporting.outputDirectory}/jacoco-ut</outputDirectory>
</configuration>
</execution>
<!--
Prepares the property pointing to the JaCoCo runtime agent which
is passed as VM argument when Maven the Failsafe plugin is executed.
-->
<execution>
<id>pre-integration-test</id>
<phase>pre-integration-test</phase>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<!-- Sets the path to the file which contains the execution data. -->
<destFile>${project.build.directory}/coverage-reports/jacoco-it.exec</destFile>
<!--
Sets the name of the property containing the settings
for JaCoCo runtime agent.
-->
<propertyName>failsafeArgLine</propertyName>
</configuration>
</execution>
<!--
Ensures that the code coverage report for integration tests after
integration tests have been run.
-->
<execution>
<id>post-integration-test</id>
<phase>post-integration-test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<!-- Sets the path to the file which contains the execution data. -->
<dataFile>${project.build.directory}/coverage-reports/jacoco-it.exec</dataFile>
<!-- Sets the output directory for the code coverage report. -->
<outputDirectory>${project.reporting.outputDirectory}/jacoco-it</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>

使用maven-surefire-plugin来执行单元测试。 将surefireArgLine赋值给argLine参数,以保证在测试执行时Jacoco agent处于运行状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<argLine>${surefireArgLine}</argLine>
<skipTests>false</skipTests>
<testFailureIgnore>true</testFailureIgnore>
<excludes>
<exclude>com.long.model.IT.**</exclude>
</excludes>
</configuration>
</plugin>

使用maven-failsafe-plugin来执行集成测试。 将failsafeArgLine赋值给argLine参数,以保证在测试执行时Jacoco agent处于运行状态。若集成测试用例和单元测试用例放在同一个项目里,必须在单元测试的surefireexclude所有集成测试用例。

通过additionalClasspathElements标签将/target/classes添加为一个额外的classpath元素,因为在classes文件夹中一些资源没有添加到jar中,但是测试使用了这些资源,若不加这个额外的classpath,则maven-failsafe-plugin插件的integration-test将不能正常执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<!-- Sets the VM argument line used when integration tests are run. -->
<argLine>${failsafeArgLine}</argLine>
<skipTests>false</skipTests>
<testFailureIgnore>true</testFailureIgnore>
<additionalClasspathElements>
<additionalClasspathElement>${basedir}/target/classes</additionalClasspathElement>
</additionalClasspathElements>
<parallel>none</parallel>
</configuration>
<executions>
<execution>
<id>integration-test</id>
<phase>integration-test</phase>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>

最后需要配置SonarQube配置信息,可以配置在Maven的setting.xml配置文件中,也可以配置在项目的中,当然可以不用profiles直接配置在properties中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<profiles>
<profile>
<id>sonar</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<sonar.jdbc.url>jdbc:mysql://192.168.3.113:3306/sonar</sonar.jdbc.url>
<sonar.jdbc.driver>com.mysql.jdbc.Driver</sonar.jdbc.driver>
<sonar.jdbc.username>yao_yinglong</sonar.jdbc.username>
<sonar.jdbc.password>yao_yinglong_passwd</sonar.jdbc.password>
<sonar.host.url>http://172.16.21.200:9000</sonar.host.url>
<sonar.binaries>src/main/java</sonar.binaries>
<sonar.sources>src/main/java</sonar.sources>
<sonar.tests>src/test/java</sonar.tests>
<sonar.language>java</sonar.language>
<sonar.coverage.exclusions>**/support/xml/**, **/entity/**</sonar.coverage.exclusions>
<sonar.cpd.exclusions>**/support/xml/**</sonar.cpd.exclusions>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
<sonar.junit.reportsPath>src/test/java</sonar.junit.reportsPath>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.jacoco.reportPaths>target/coverage-reports/jacoco-ut.exec</sonar.jacoco.reportPaths>
<sonar.jacoco.itReportPath>target/coverage-reports/jacoco-it.exec</sonar.jacoco.itReportPath>
</properties>
</profile>
</profiles>

当然为了简化配置可以不配置jacoco-maven-plugin的集成测试相关执行目标,也没有必要配置maven-failsafe-plugin插件,去掉maven-surefire-plugin插件中排除的集成测试,同时可以将sonar.jacoco.itReportPath配置为target/coverage-reports/jacoco-ut.exec甚至不配。

但是即使这样以上的配置还是过于庞杂,如果很多项目使用该类容,可以创建一个超级POM,将这些内容放在超级POM中,用到的项目集成该超级POM即可极大的简化配置。

但是这样配置,项目在测试环境、预发布环境、生产环境或者一些其他的不需要使用导SonarQube的环境,也会执行SonarQube扫描。有可能这些环境与搭建的SonarQube的服务网络不通导致项目不能正常构建。在构建参数中添加-Dsonar.skip=true命令即可跳过SonarQube正常构建项目。如果使用Jenkins可以在Build的Goals and options中进行添加该命令。