jenkins流水线整合jacoco与sonar(一)
jacoco单元测试整合
1.项目引入jacoco依赖
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.2</version>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.2</version>
<configuration>
<destFile>${basedir}/target/coverage-reports/jacoco-unit.exec</destFile>
<dataFile>${basedir}/target/coverage-reports/jacoco-unit.exec</dataFile>
<includes>
<!--指定检测的目录,请注意项目的控制层和服务层包命名是否和配置相同-->
<include>**/service/**</include>
<include>**/controller/**</include>
</includes>
<output>file</output>
<append>true</append>
</configuration>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<phase>test-compile</phase>
</execution>
<execution>
<id>jacoco-site</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
2.jenkins流水线脚本编写
stage('Unit Test') {
if (enableUnitTest == "1") {
println("#############################################开始单元测试##################################################")
withEnv(["JAVA_HOME=/root/jenkins/tools/${jdkVersion}", "MVN_HOME=/root/jenkins/tools/maven3"]) {
sh '"$MVN_HOME/bin/mvn" clean jacoco:prepare-agent package jacoco:report'
}
//找到输出的xml文件,解析传入接口
xmlOut = sh(script: "ls /root/jenkins/workspace/${jobName}/target/site/jacoco/jacoco.xml", returnStatus: true)
//覆盖率文件存在
if (xmlOut == 0) {
//将覆盖率文件复制到nginx
sh(script: "cp -r /root/jenkins/workspace/${jobName}/target/site/jacoco/ /root/unit_test/${jobName}_${pipeLineId}/")
def filePath = "target/site/jacoco/jacoco.xml"
def xmlContent = readFile file: filePath; encoding: "UTF-8"
println(xmlContent)
def toJson = {
input ->
groovy.json.JsonOutput.toJson(input)
}
def body = [
unitTestResultXml: "$xmlContent",
jobName : "$jobName",
pipeLineId : "$pipeLineId",
codeType : "java"
]
def response = httpRequest acceptType: 'APPLICATION_JSON', contentType: 'APPLICATION_JSON', httpMode: 'POST', requestBody: toJson(body), timeout: 10000, validResponseCodes: '100:599', url: "http://${host}${qualityApi}unitTest/getScoreResult"
println("unitTest Response:" + response)
println("response.data:" + response.content)
def responseBodyJson = readJSON text: response.content
def data = responseBodyJson.data
println(data)
if (response.status == 200) {
if (data.pass) {
println("#############单元测试通过#################")
println("##################################" + responseBodyJson.message + " 分支覆盖率:" + data.branchCoverage + "########################################")
} else {
println("##################################" + responseBodyJson.message + " 分支覆盖率:" + data.branchCoverage + "########################################")
sh "exit 1"
}
} else {
println("#############单元测试失败#################")
println("接口响应异常")
println(responseBodyJson)
sh "exit 1"
}
}
//覆盖率文件不存在
else if (xmlOut == 2) {
println("#############单元测试失败#################")
println("##################################jacoco.xml不存在#############################");
println("请检查jacoco的相关依赖是否完整")
sh "exit 1"
} else {
println("#############单元测试失败#################")
println("##################################命令有误,请检查#############################")
sh "exit 1"
}
} else {
println("#############################################单元测试未启用,跳过单元测试##################################################")
}
}
- 流水线语法可在jenkins 流水线语法的生成器中生成相应的demo脚本,再根据需要自己修改
- jacoco脚本可在jacoco官网查到
- 踩坑,发送post请求时,json数据转换先在脚本首行引入import groovy.json.JsonSlurper
3.jacoco扫描结果集成
执行流水线后,取到扫描结果调用对应的接口,解析相应的xml文件内容,解析时花了不少时间解决一系列坑,核心代码如下
//截取<!DOCTYPE report PUBLIC "-//JACOCO//DTD Report 1.1//EN" "report.dtd"> 解决解析报错
StringBuilder builder = new StringBuilder(unitTestResultXml);
int startIndex = builder.indexOf("<!");
int endIndex = builder.indexOf(".dtd\">") + 6;
unitTestResultXml = builder.replace(startIndex, endIndex, "").toString();
//解析xml字符串内容
Document document = null;
try {
document = DocumentHelper.parseText(unitTestResultXml);
} catch (DocumentException e) {
log.error("解析xml出错", e);
throw new BusinessException(false, QualityEnum.XML_PARSE_EXCEPTION.getCode(), QualityEnum.XML_PARSE_EXCEPTION.getMassage());
}
Element rootElement = document.getRootElement();
List elements = rootElement.elements("counter");
Iterator iterator = elements.iterator();
while (iterator.hasNext()) {
Element element = (Element) iterator.next();
//获取参数
String type = element.attributeValue("type");
int covered = Integer.parseInt(element.attributeValue("covered"));
int missed = Integer.parseInt(element.attributeValue("missed"));
double coverage = Double.parseDouble(String.valueOf(NumberUtil.mul(NumberUtil.roundStr(NumberUtil.div(covered, NumberUtil.add(covered, missed)), 2), "100")));
if (type.equals(UnitTestAttributeEnum.BRANCH.getAttribute())) {
unitTestResult.setBranchCovered(covered)
.setBranchMissed(missed)
.setBranchCoverage(coverage);
break;
}
}
return unitTestResult;
经讨论决定,只取了分支覆盖率作为评判标准,再根据不同级别的项目标准给出测试结果,至此jacoco的集成就完成了。