转载:https://ningyu1.github.io/site/post/77-jenkins-sonarqube-jacoco-junit/
Published on: 2018-04-12
Tags: jenkins sonar sonarqube jacoco junit testng
当我们使用持续集成Jenkins
的时候经常会结合一系列的插件使用,这里就说一下Jenkins
集成Sonar
做代码质量管理以及Junit(testng)
、JaCoCo
做单元测试和覆盖率的时候遇到的问题。
首先我们的工程使用maven
构建,单元测试使用testng
编写,在使用jenkins
之前我们应该在本地使用maven调通所有的单元测试以及test coverage
的问题。
我们使用maven-surefire-plugin
来生成单元测试报告,使用jacoco-maven-plugin
来生成test coverage
报告。下面我给出以下我使用的标准配置
pom.xml的标准配置
org.slf4j
slf4j-api
org.testng
testng
6.4
test
true
junit
junit
test
true
org.jacoco
jacoco-maven-plugin
0.8.1
org.apache.maven.plugins
maven-surefire-plugin
2.5
false
${argLine} -Dfile.encoding=UTF-8
org.apache.maven.plugins
maven-deploy-plugin
false
org.jacoco
jacoco-maven-plugin
0.8.1
false
prepare-agent
${basedir}/target/coverage-reports
report
test
report
根据上面配置执行下来的报告生成的目录结构如下:
classes
是源代码编译生成的字节码目录coverage-reports
是单元测试覆盖率报告生成目录surefire-reports
是单元测试报告生成目录test-classes
是单元测试代码编译生成的字节码目录jacoco.exec
是用于生成单元测试可执行文件下面我说一下我们会遇到的常规问题
[INFO] --- maven-surefire-plugin:2.5:test (default-test) @ tools ---
[INFO] Tests are skipped.
单元测试被跳过,这个可以通过maven-surefire-plugin
插件的configuration
来配置不跳过,如下配置:
org.apache.maven.plugins
maven-surefire-plugin
2.5
false
配置skipTests
属性而不是skip
属性这里需要注意一下,有很多人配置的skip
属性
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running TestSuite
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
=====��һ��===============
=====��һ��===============
=====���¼���===============
单元测试输出信息乱码,这个可以通过maven-surefire-plugin
插件的configuration
来配置字符编码,如下配置:
org.apache.maven.plugins
maven-surefire-plugin
2.5
false
-Dfile.encoding=UTF-8
到这里我们就可以去taget/surefire-reports
目录下查看单元测试报告。
[INFO] --- jacoco-maven-plugin:0.8.1:report (report) @ tools ---
[INFO] Skipping JaCoCo execution due to missing execution data file.
jacoco
执行被跳过,原因是没有找到jacoco
可执行文件jacoco.exec
。
这个时候我们去target
目录下是看不到jacoco.exec
文件的,有的版本名字叫jacoco-junit.exec
。
理论上执行的时候会自动生成exec文件,但是为什么没有生成?我们看一下执行日志
[INFO] --- jacoco-maven-plugin:0.8.1:prepare-agent (default) @ tools ---
[INFO] argLine set to -javaagent:D:\\javatools\\mvnrepository\\org\\jacoco\\org.jacoco.agent\\0.8.1\\org.jacoco.agent-0.8.1-runtime.jar=destfile=D:\\javatools\\workspace\\framework\\tools\\target\\jacoco.exec
jacoco.exec
的生成是根据-javaagent
的方式来生成的,我们有可以看到jacoco-maven-plugin
指定了argLine
参数,但是为什么没有生效?
原因是我们上面指定过单元测试编码,使用的就是argLine
参数,因此这个问题应该是上面的编码参数指定后没有带入插件添加的-javaagent
参数,那如何解决?查看下面配置:
org.apache.maven.plugins
maven-surefire-plugin
2.5
false
${argLine} -Dfile.encoding=UTF-8
在argLine
中增加变量${argLine}
后面再增加自动以的参数
如果通过配置手动的指定jacoco.exec
文件的生成路径也需要注意也可能会出现这个问题,生成exec的路径指定在哪里,report执行的时候就需要通过dataFile
来指定exec的路径,让程序知道正确的exec路径,比如说:
org.jacoco
jacoco-maven-plugin
0.8.1
false
${basedir}/target/coverage-reports/jacoco.exec
prepare-agent
${basedir}/target/coverage-reports/jacoco.exec
${basedir}/target/coverage-reports
report
test
report
上面通过configuration
的destFile
来自定义jacoco.exec
的生成路径,下面在report
的时候需要通过dataFile
来指定对应的jacoco.exec
的路径。
首先去Jenkins
上安装JaCoCo plugin
插件,插件的安装就跳过了,插件安装好后,在job中如何配置?
这里需要注意的配置
classes
目录不是test-classes
目录,如果有多个可以指定多个src/main/java
目录,如果有多个可以指定多个。配置好之后执行job会看到如下的日志:
INFO: ------------------------------------------------------------------------
Injecting SonarQube environment variables using the configuration: SonarQube
[JaCoCo plugin] Collecting JaCoCo coverage data...
[JaCoCo plugin] **/jacoco.exec;**/classes;src/main/java; locations are configured
Injecting SonarQube environment variables using the configuration: SonarQube
Injecting SonarQube environment variables using the configuration: SonarQube
[JaCoCo plugin] Number of found exec files for pattern **/jacoco.exec: 1
[JaCoCo plugin] Saving matched execfiles: /var/lib/jenkins/workspace/cc-framework-tools/target/coverage-reports/jacoco.exec
[JaCoCo plugin] Saving matched class directories for class-pattern: **/classes:
[JaCoCo plugin] - /var/lib/jenkins/workspace/cc-framework-tools/target/classes 5 files
[JaCoCo plugin] Saving matched source directories for source-pattern: src/main/java:
[JaCoCo plugin] - /var/lib/jenkins/workspace/cc-framework-tools/src/main/java 5 files
[JaCoCo plugin] Loading inclusions files..
[JaCoCo plugin] inclusions: []
[JaCoCo plugin] exclusions: []
[JaCoCo plugin] Thresholds: JacocoHealthReportThresholds [minClass=0, maxClass=0, minMethod=0, maxMethod=0, minLine=0, maxLine=0, minBranch=0, maxBranch=0, minInstruction=0, maxInstruction=0, minComplexity=0, maxComplexity=0]
[JaCoCo plugin] Publishing the results..
[JaCoCo plugin] Loading packages..
[JaCoCo plugin] Done.
[JaCoCo plugin] Overall coverage: class: 50, method: 54, line: 48, branch: 40, instruction: 55
Finished: SUCCESS
出现上面日志就证明配置成功并且可以看到报告,如果出现下面的日志就证明配置的目录没有扫到classes,需要修改Path to class directories
目录的配置
Overall coverage: class: 0, method: 0, line: 0, branch: 0, instruction: 0
最终结果如下图:
首先去Jenkins上
安装SonarQube plugin
插件,插件的安装就跳过了,插件安装好后,在jenkins
的系统配置中配置sonar
服务器信息,如下
配置好后在job的配置中增加SonarQube
的支持,如下
Prepare SonarQube Scanner environment
Execute SonarQube Scanner
Execute SonarQube Scanner
中增加Analysis properties
# required metadata
# 项目key
sonar.projectKey=com.domian.package:projectName
# 项目名称
sonar.projectName=tools
# 项目版本,可以写死,也可以引用变量
sonar.projectVersion=${VER}
# 源文件编码
sonar.sourceEncoding=UTF-8
# 源文件语言
sonar.language=java
# path to source directories (required)
# 源代码目录,如果多个使用","分割 例如:mode1/src/main,mode2/src/main
sonar.sources=src/main
# 单元测试目录,如果多个使用","分割 例如:mode1/src/test,mode2/src/test
sonar.tests=src/test
# Exclude the test source
# 忽略的目录
#sonar.exclusions=*/src/test/**/*
# 单元测试报告目录
sonar.junit.reportsPath=target/surefire-reports
# 代码覆盖率插件
sonar.java.coveragePlugin=jacoco
# jacoco.exec文件路径
sonar.jacoco.reportPath=target/coverage-reports/jacoco.exec
# 这个没搞懂,官方示例是配置成jacoco.exec文件路径
sonar.jacoco.itReportPath=target/coverage-reports/jacoco.exec
具体的参数可以查看官方文档:《Analysis Parameters》
配置好之后执行job后去Sonar
上只看到了单元测试的信息,没有看到单元测试覆盖率的信息,关于这个问题我们分析job执行的日志,如下:
16:01:17.455 INFO - Sensor JaCoCoOverallSensor
16:01:17.470 INFO - Analysing /var/lib/jenkins/workspace/cc-framework-tools/target/coverage-reports/jacoco.exec
16:01:17.481 INFO - No JaCoCo analysis of project coverage can be done since there is no class files.
16:01:17.481 INFO - Sensor JaCoCoOverallSensor (done) | time=26ms
16:01:17.482 INFO - Sensor JaCoCoSensor
16:01:17.482 INFO - No JaCoCo analysis of project coverage can be done since there is no class files.
16:01:17.482 INFO - Sensor JaCoCoSensor (done) | time=0ms
16:01:17.482 INFO - Sensor Code Colorizer Sensor
说的是没找到class文件所以jacoco
不能进行分析,问题很明显是没有找到class类,难道它不是去maven
标准的target/classes
下找文件么?
但是找到了这篇文章:《Jenkins, JaCoCo, and SonarQube Integration With Maven》,看到里面在pom.xml中配置了一些参数给我了启发,发现有个参数sonar.binaries
指定的是classes目录,可以插件的有些参数不兼容maven,在官方的配置中可以看到这样的字样: Not compatible with Mave
和Compatible with Maven
,能看到有写参数兼容maven默认路径有些不兼容。
随后再官方文档中也找到了与jenkins继承的properties配置说明:《Triggering Analysis on Hudson Job》
# path to project binaries (optional), for example directory of Java bytecode
# java字节码目录
sonar.binaries=binDir
最终给出Execute SonarQube Scanner
中的Analysis properties
完成配置参数如下:
# required metadata
# 项目key
sonar.projectKey=com.domian.package:projectName
# 项目名称
sonar.projectName=tools
# 项目版本,可以写死,也可以引用变量
sonar.projectVersion=${VER}
# 源文件编码
sonar.sourceEncoding=UTF-8
# 源文件语言
sonar.language=java
# path to source directories (required)
# 源代码目录,如果多个使用","分割 例如:mode1/src/main,mode2/src/main
sonar.sources=src/main/java
# 单元测试目录,如果多个使用","分割 例如:mode1/src/test,mode2/src/test
sonar.tests=src/test/java
# java字节码目录
sonar.binaries=target/classes
# 单元测试报告目录
sonar.junit.reportsPath=target/surefire-reports
# 代码覆盖率插件
sonar.java.coveragePlugin=jacoco
# jacoco插件版本
jacoco.version=0.8.1
# jacoco.exec文件路径
sonar.jacoco.reportPath=target/coverage-reports/jacoco.exec
全部配置修改完后执行job后去Sonar
上查看具体的信息如下: