SpringBoot系统持续集成持续交付实战
实战执行流程
工程准备
SpringBoot系统
- Github地址:https://github.com/jinglv/spring-boot-restful-api.git
- 该项目是一个纯接口的项目,下载后打包成jar包即可
接口自动化测试工程
SpringBoot系统持续交付
git clone SpringBoot项目,使用Idea打开该项目,查看工程的目录
下载jacoco相关包到部署服务器上,下载地址:https://www.jacoco.org/jacoco/
1
2
3
4
5
6[root@lvjing ~]# cd /usr/local/
[root@lvjing local]# ls
aegis bin etc games include jacoco jdk1.8 lib lib64 libexec maven sbin share sonar-scanner src tomcat9
[root@lvjing local]# cd jacoco/
[root@lvjing jacoco]# ls
coverage doc index.html lib test
Dockerfile镜像打包的内容如下:
1
2
3
4
5
6
7
8FROM java:8
MAINTAINER jinglv
ENV TZ "Asia/Shanghai"
ENV LANG C.UTF-8
VOLUME /tmp
ADD spring-boot-restful-api-0.0.1-SNAPSHOT.jar restful.jar
ENTRYPOINT ["java","-javaagent:/usr/local/jacocoagent.jar=includes=*,output=tcpserver,append=true,address=*,port=6301,destfile=/usr/local/jacoco.exec","-Djava.security.egd=file:/dev/./urandom","-jar","restful.jar"]
EXPOSE 8988项目需要统计测试覆盖率,则在项目启动的时候需要使用jacocoagent.jar,因此我们在启动Docker实例时需要引入jacocoagent.jar
Jenkinsfile pipeline脚本如下:
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114pipeline {
agent {
label 'master'
}
environment {
cred_id = 'b4d58207-0fa3-43f5-bf1d-c635025a7684124'
docker_image_name = 'restful_api'
docker_container_name = 'irestful_api'
}
parameters {
string(name: 'branch', defaultValue: 'main', description: 'Git branch')
string(name: 'pomPath', defaultValue: 'pom.xml', description: 'pom.xml的相对路径')
string(name: 'lineCoverage', defaultValue: '20', description: '单元测试代码覆盖率要求(%),小于此值pipeline将会失败!')
}
stages {
stage('检出代码') {
steps {
git credentialsId: cred_id, url: 'https://gitee.com/jeanlv/spring-boot-restful-api.git', branch: "$params.branch"
}
}
stage('Maven编译打包并单元测试') {
steps {
// 注入jacoco插件配置,clean test执行单元测试代码. All tests should pass.
sh '''
. ~/.bash_profile
cd ${WORKSPACE}
mvn org.jacoco:jacoco-maven-plugin:prepare-agent -f ${pomPath} clean install -Dautoconfig.skip=true -Dmaven.test.skip=false
'''
}
}
stage('SonarQube代码质量扫描') {
steps {
sh '''
. ~/.bash_profile
cd ${WORKSPACE}
mvn sonar:sonar -Dsonar.projectKey=spring-boot-restful-api -Dsonar.host.url=http://60.205.228.49:9000/ -Dsonar.login=053ed1077e82a2bb36eebf619d24d75b8c5738b9 -Dsonar.branch.name=${branch}
'''
junit '**/target/surefire-reports/*.xml'
// 配置单元测试覆盖率要求,未达到要求pipeline将会fail,code coverage.LineCoverage>20%.
jacoco changeBuildStatus: true, maximumLineCoverage: "$params.lineCoverage"
}
}
stage('停止 / 删除 现有Docker Container/Image ') {
steps {
script {
try {
sh 'docker stop $docker_container_name'
} catch (exc) {
echo 'The container $docker_container_name does not exist'
}
try {
sh 'docker rm $docker_container_name'
} catch (exc) {
echo 'The container $docker_container_name does not exist'
}
try {
sh 'docker rmi $docker_image_name'
} catch (exc) {
echo 'The docker image $docker_image_name does not exist'
}
}
}
}
stage('生成新的Docker Image') {
steps {
sh '''
cd ${WORKSPACE}/docker
rm -f spring-boot-restful-api-0.0.1-SNAPSHOT.jar
cp ${WORKSPACE}/target/spring-boot-restful-api-0.0.1-SNAPSHOT.jar .
docker build -t $docker_image_name .
'''
}
}
stage('启动新Docker实例') {
steps {
sh '''
docker run -d --name $docker_container_name -p 8988:8988 -p 6301:6301 -v /usr/local/jacoco/lib/jacocoagent.jar:/usr/local/jacocoagent.jar $docker_image_name
'''
}
}
}
post {
always {
script {
println "Do some actions when always need."
}
}
failure {
script {
println "Do some actions when build failed."
}
}
success {
script {
println "Here we kickoff run job SpringBoot-Restful-Api-Test-Pipeline"
job_run_result = build job: 'SpringBoot-Restful-Api-Test-Pipeline', propagate: false, wait: true
println job_run_result.getResult()
}
}
}
}查看pipeline脚本的节点,了解到持续交付执行的节点步骤,并在执行成功后触发’SpringBoot-Restful-Api-Test-Pipeline’Job,当中只要有一个节点执行失败,则Job会输出失败,在此我们可以配置邮件、企业微信、钉钉通知等。
注意:该SpringBoot工程为演示方便,没有使用数据库存储数据,如果涉及数据库,则需要添加数据库配置,具体介绍详看文章Jenkins Docker部署持续交付实战
接口自动化测试持续集成
git clone接口自动化测试工程,使用Idea打开该项目,查看工程的目录
下载sonar-scanner到Jenkins部署服务器上,下载地址:https://docs.sonarqube.org/latest/analysis/scan/sonarscanner/
1
2
3
4
5
6[root@lvjing ~]# cd /usr/local/
[root@lvjing local]# ls
aegis bin etc games include jacoco jdk1.8 lib lib64 libexec maven sbin share sonar-scanner src tomcat9
[root@lvjing local]# cd sonar-scanner/
[root@lvjing sonar-scanner]# ls
bin conf jre lib下载完成后,需要在conf/sonar-scanner.properties文件中,配置SonarQube平台的地址及登录用户名和密码
1
2
3
4
5
6
7
8
9
10
11#Configure here general information about the environment, such as SonarQube server connection details for example
#No information about specific project should appear here
#----- Default SonarQube server
http://60.205.228.49:9000/ =
#----- Default source code encoding
#sonar.sourceEncoding=UTF-8
admin =
admin1234567 =
Jenkinsfile pipeline脚本如下:
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
81pipeline {
agent {
label 'master'
}
environment {
cred_id = 'b4d58207-0fa3-43f5-bf1d-c635025a7684'
}
parameters {
string(name: 'branch', defaultValue: 'master', description: 'Git branch')
}
stages {
stage('检出代码') {
steps {
git credentialsId: cred_id, url: 'https://gitee.com/jeanlv/api-object-auto.git', branch: "$params.branch"
}
}
stage('Maven执行测试') {
steps {
sh '''
. ~/.bash_profile
cd ${WORKSPACE}
mvn clean install
'''
}
}
stage('JaCOCO Dump数据') {
steps {
sh '''
java -jar /usr/local/jacoco/lib/jacococli.jar dump --address 127.0.0.1 --port 6301 --destfile /root/jacoco-project/jacoco_docker.exec
'''
}
}
stage('JaCOCO测试报告生成') {
steps {
sh '''
cd ..
cd SpringBoot-Restful-Api-Docker-Pipeline
pwd
java -jar /usr/local/jacoco/lib/jacococli.jar report /root/jacoco-project/jacoco_docker.exec --classfiles=./target/classes --sourcefiles=./src/main/java --html /root/jacoco-project/report/ --xml /root/jacoco-project/report/jacoco.xml
'''
}
}
stage('SonarQube分析') {
steps {
sh '''
cd ..
cd SpringBoot-Restful-Api-Docker-Pipeline
pwd
/usr/local/sonar-scanner/bin/sonar-scanner -Dsonar.coverage.jacoco.xmlReportPaths=/root/jacoco-project/report/jacoco.xml -Dsonar.projectKey=spring-boot-restful-api-test -Dsonar.projectName=spring-boot-restful-api-test -Dsonar.language=java -Dsonar.sourceEncoding=UTF-8 -Dsonar.core.codeCoveragePlugin=jacoco -Dsonar.sources=./src/main/java -Dsonar.java.binaries=./target
'''
}
}
}
post {
always {
script {
println "Do some actions when always need."
allure includeProperties: false, jdk: '', results: [[path: 'target/allure-results']]
}
}
failure {
script {
println "Do some actions when build failed."
}
}
success {
script {
println "Do some actions when build success."
}
}
}
}查看pipeline脚本的节点,了解到持续集成执行的节点步骤,在脚本执行完成后,输出Allure接口测试报告
Jenkins创建Job并执行
需要创建两个Job,一个是SpringBoot系统持续交付和接口自动化测试持续集成,两个Job均为Jenkins流水线,具体配置详见Jenkins介绍,本篇不在具体介绍
SpringBoot-Restful-Api-Docker-Pipeline在执行成功后,会自动触发SpringBoot-Restful-Api-Test-Pipeline Job,下面我们查看两个Job具体执行的流水线
SpringBoot-Restful-Api-Docker-Pipeline的流水线流程
SpringBoot-Restful-Api-Test-Pipeline的流水线流程
SonarQube平台查看结果
我们看到上面的Jenkins Job都已执行成功,结果也均已上传到SonarQube平台上,这是我们可以到SonarQube平台查看结果
我们明确的看到,单元测试和接口测试完成后,Jacoco得出的结果,略有不同。
其实我们看到的结果,差的不是很多,为什么又要做单元测试还要做接口测试呢?我们可以从以下几方面开看:
- 角色不同
- 单元测试 – 开发工程师
- 接口测试 – 测试工程师
- 测试重点不同
- 单元测试 – 系统内部逻辑
- 接口测试 – 接口的输入和输出
- 单元测试和接口测试的关系
- 接口测试是对单元测试的一个补充,在接口测试阶段我们可以考虑到业务需求相关数据,对数据的可行性、容错性都可以在该阶段进行充分的测试