其他博文连接

gitlab CI中单元测试与集成测试的研究与实践

配置说明

Gitlab

  • 系统:Ubuntu 16.04 Server
  • 内存:4G
  • IP:192.168.23.100
  • Dokcer Version : 18.09.0

Gitlab Runner

  • 系统:Ubuntu 16.04 Server
  • 内存:4G
  • IP:192.168.23.102
  • Dokcer Version : 18.09.0

Sonarqube

  • 系统:Ubuntu 16.04 Server
  • 内存:4G
  • IP:192.168.23.101
  • Dokcer Version : 18.09.0

CI流程图

在这里插入图片描述
上图是我理解的整个流程:

  • 开发人员提交代码
  • Gitlab出发CI
  • Gitlab-Runner进行开始流水线
  • 进行项目构建,gradle bootjar打出一个可执行的Spring Boot的Jar包
  • 进行sonar静态代码审查,如果BUG数超过一定限制则CI失败,开发者需要修改相应的BUG后重新提交
  • 进行单元测试gradle test
  • 进行自动化集成测试,我的理解是可以模拟第三方应用对接口进行测试。不关心接口内部实现及调用,只关心输入输出
  • 当单元测试和集成测试都成功后,进行部署
  • 结束

以上只是个人理解,如果有不妥之处请提出来。本篇暂时不讲持续部署(CD)

需要解决的问题

实际开发中,都是多人进行开发。提交的时候也可能是多人同时提交,这时会触发多个CI。因为每个开发者开发的功能点不同,所以需要在不同的环境下进行CI,这样就要求不同的CI环境能够隔离。通过Gitlab-Runner的Docker执行器能够很好的做到这点,但是CI的数据库怎么指定?总不能每个人都改配置文件,修改成自己的数据库吧。所以这时需要实现每个分支的CI能够对应不同的数据库,这点可以通过启动jar时指定环境变量,比如每次提交的Commit号等,通过使用这个环境变量作为数据库名就可以实现这点(当然也可以使用容器内的数据库,这样也可以隔离,但是本人没有实现所以不做介绍了)。

代码编写

项目代码

实现一个简单的新增学生信息来作为示例

代码在最后链接中

单元测试

这里就随便写个示例,单元测试的代码项目中都有

Service单元测试

在最后的代码链接中

Controller单元测试

可参考:博客园的:SpringBoot系列: 单元测试

集成测试

这里我的思路是新建一个仓库,这个仓库的代码模拟服务调用者。数据的话可在integration-test通过gradle命令装载集成测试数据(实现可以在test中实现代码,通过gradle或其他方式执行数据装载)。在gitlab-ci的integration-test阶段,通过git把服务调用者clone下来,通过gradle打成可执行jar,然后运行。具体实现掠过

提供专门用于测试的配置文件application-test.yml

server:
  port: 8880
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    # ${CI_COMMIT_SHA}指的是每次提交的commit号,我们每次使用这个作为数据库名,将不同用户的ci隔开,数据库在ci的第一阶段创建
    url: jdbc:mysql://192.168.23.102:3306/${CI_COMMIT_SHA}?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username : root
    password : root123
    driverClassName : com.mysql.jdbc.Driver
  jpa:
    hibernate:
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
      ddl-auto: update
    show-sql: true

.gitlab-ci.yml编写

gitlab-runner server 安装mysql-client

这里提供一个mysql的镜像,能够通过shell创建数据库: virtuex/mysql_env:mysql-5.7-openjdk-7,dockerhub地址

.gitlab-ci.yml

下面是.gitlab-ci.yml的配饰文件,每部的作用在注释中体现

# 指定基础镜像
image: virtuex/base_java_env:gradle-4.10.2-openjdk-7-openjdk-8-docker-18

# 定义stage
stages:
  - build_db
  - build
  - unit-test
  - integration-test

# 这个job主要是为了创建数据库,官方提供的service因为我没有使用成功,所以这里采用alphin镜像,并安装mysql客户端,以执行mysql命令
gitab_mysql_service:
  stage: build_db
  image: alpine:latest
  script:
    - apk --no-cache add mysql-client
    - sh src/test/bin/create_database.sh

# 因为基础镜像默认用的1.7,这里切换成1.8
before_script:
  - echo "Reset JDK..."
  - export JAVA_HOME=$JAVA8_HOME
  - export PATH=${JAVA_HOME}/bin:$PATH

# 这个job主要是为了生成build/classes/test这个文件夹,否则下个阶段执行sonar命令会失败
build_job:
  stage: build
  script:
    - echo "Release build..."
    - gradle testClasses

# 单元测试、代码静态检查、单元测试覆盖率检查等
test_job:
  stage: unit-test
  script:
    - echo "Unit Tests run..."
    - gradle test
    - gradle jacocoTestReport
    - gradle testClasses
    - gradle -b sonarqube.gradle sonarqube -Dsonar.analysis.mode="${MODE}" -Dsonar.gitlab.project_id=$CI_PROJECT_PATH -Dsonar.gitlab.commit_sha=$CI_COMMIT_SHA -Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME

# 集成测试阶段,运行springboot程序,并执行自定义的集成测试流程
integration_test_job:
  stage: integration-test
  variables:
    GRADLE_MODE: "check"
    MODE: "preview"
  script:
  # 打成可直接运行的Springboot的jar
    - gradle bootJar
    # 切换成1.8的jdk
    - export JAVA_HOME=$JAVA8_HOME
    - export PATH=${JAVA_HOME}/bin:$PATH
    # 指定以用于测试阶段的配置运行,这里使用nohup,否则后打死在这个命令而不往后进行
    - nohup java -jar -Dspring.profiles.active=test build/libs/ci_test-1.0-SNAPSHOT.jar &
    #####################################################################
    # 下面是进行集成测试阶段,具体的流程可自己定义,我这里是我自己的一个思路
    #####################################################################

    - echo "Integration testing run..."
    - echo "git clone xxxx.git"
    # 可以结合application插件,打成可执行jar
    - echo "gradle distZip"
    # zipb包的目录大概是:#  - xxx.zip
    #     -/bin
    #        -/启动脚本
    #     -/lib
    #        -/依赖的jar
    - echo "unzio xxx.zip"
    - echo "sh /xx/bin/start.sh"
    - echo "start integeration testing!"

create_database.sh

通过shel连接到另一台主机并创建数据库

#!/bin/sh
 #数据库信息地址,这里的数据库是一个固定的数据库
HOSTNAME="192.168.23.102" 
PORT="3306"
USERNAME="root"
PASSWORD="root123"
#创建数据库
#其中CI_COMMIT_SHA是Gitalb Ci提供的变量,保存每次提交的commit号,这里使用commit号作为数据库名以保证每次提交都是不同的
create_db_sql="create database IF NOT EXISTS $CI_COMMIT_SHA"
#远程创建命令
mysql -h${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} -e "${create_db_sql}"

运行结果

首先放一张各个流程的整体运行结果
在这里插入图片描述

gitab_mysql_service任务

在这里插入图片描述
这一步是为了创建数据库,其中描述了第一阶段的构建流程,我们本次提交的commit号是c96641f6开头的,可以看到数据库中也成功创建了该数据库,如下图:
在这里插入图片描述

test_job任务

这一步为了执行单元测试等
在这里插入图片描述

test_job任务

在这里插入图片描述
到这里初步完成了设计思路,具体细节还需完善。

项目代码

测试用代码链接

测试用虚拟机下载地址

因为虚拟机比较大,已上传到百度网盘:
链接:https://pan.baidu.com/s/14vk8gLpblx77B8oB1Kn5lA
提取码:hs3m

  • 192.168.23.100 : gitlab的地址,可直接访问:http://192.168.23.100
  • 192.168.23.101 :sonarqube地址,可直接访问: http://192.168.23.101:9000 ,应用在docker中,如果不能使用请自行开启
  • 192.168.23.102 : gitlab-runner地址,已安装的是docker执行器,可重新注册替换成其他的

其中192.168.23.102是runner的所在地址,如果docker0网络使用过程中出现错误可参考另一篇博文物理机没法访问虚拟机docker中的应用

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐