【Jenkins使用之九】jenkins自動測試


環境
  CentOS Linux release 7.6.1810
  jdk1.8.0_65
  apache-tomcat-8.5.45
  Jenkins-2.235.5
  apache-maven-3.6.3
  git-2.9.5
  gradle-6.6.1
  SonarQube-6.7.7(LTS)
  sonar-scanner-cli-4.2.0.1873
拓撲:
  node1:安裝GitLab、SonarQube
  node2:安裝Jenkins、Git、MAVEN

我們開發的軟件都需要測試,才能上線,軟件測試按階段划分:
(1)單元測試(unit testing),是指對軟件中的最小可測試單元進行檢查和驗證。
(2)集成測試(integration testing),是單元測試的下一階段,是指將通過測試的單元模塊組裝成系統或子系統,再進行測試,重點測試不同模塊的接口部門。
(3)系統測試(system testing),指的是將整個軟件系統看做一個整體進行測試,包括對功能、性能,以及軟件所運行的軟硬件環境進行測試。
(4)驗收測試(acceptance testing),指的是在系統測試的后期,以用戶測試為主,或有測試人員等質量保障人員共同參與的測試,它也是軟件正式交給用戶使用的最后一道工序。

一般性能測試:指的是讓被測系統在正常的軟硬件環境下運行,不向其施加任何壓力的性能測試。
穩定性測試也叫可靠性測試(reliability testing):是指連續運行被測系統檢查系統運行時的穩定程度。
負載測試(load testing):是指讓被測系統在其能忍受的壓力的極限范圍之內連續運行,來測試系統的穩定性。
壓力測試(stress testing):是指持續不斷的給被測系統增加壓力,直到將被測系統壓垮為止,用來測試系統所能承受的最大壓力。

一、單元測試
每種編程語言都有單元測試框架,比如java語言中JUnit,執行單元測試的工作一般由自動化構建工具完成,但是構建工具只是執行了單元測試的命令,將單元測試調用起來,構建工具不會幫我們創建單元測試用例,單元測試都是開發事先寫好的。

1、Junit單元測試報告
這里演示一個jenkins使用JUnit插件收集展示單元測試報告的示例:
(1)Jenkins安裝JUnit插件
(2)創建一個MultiBranch pipeline 工程
maven項目pom.xml中引入maven-surefire-plugin插件

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <!--表示執行任何子目錄下所有命名以Tests結尾的java類 -->
        <includes>
            <include>**/*Tests.java</include>
        </includes>
        <!--表示不執行任何子目錄下所有命名以Test開頭的java類 -->
        <!--
        <excludes>
            <exclude>**/Test*.java</exclude>
        </excludes>
        -->
    </configuration>
</plugin>

完整pom示例:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.macro.mall</groupId>
    <artifactId>mall-tiny</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <name>mall-tiny</name>
    <description>mall-tiny project</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <skipTests>false</skipTests>
        <!--該方法有漏洞,容易被黑客遠程放入挖礦機鏡像,開啟需做好防范,
        年少無知的我,開放2375,沒做ip限制,被拉去挖礦了。。。
        推薦使用CA加密端口-->
        <docker.host>http://192.168.118.106:2375</docker.host>
        <docker.maven.plugin.version>1.2.2</docker.maven.plugin.version>
        <druid.version>1.1.10</druid.version>
        <hutool.version>4.5.7</hutool.version>
        <swagger2.version>2.9.2</swagger2.version>
        <swagger-models.version>1.6.0</swagger-models.version>
        <swagger-annotations.version>1.6.0</swagger-annotations.version>
        <mysql-connector.version>8.0.16</mysql-connector.version>
        <jjwt.version>0.9.0</jjwt.version>
        <mybatis-plus.version>3.3.2</mybatis-plus.version>
        <velocity.version>2.2</velocity.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencies>
        <!--SpringBoot通用依賴模塊-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--SpringBoot校驗框架-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <!--集成druid連接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <!--Mysql數據庫驅動-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql-connector.version}</version>
        </dependency>
        <!--Swagger-UI API文檔生產工具-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${swagger2.version}</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${swagger2.version}</version>
        </dependency>
        <!--解決Swagger 2.9.2版本NumberFormatException-->
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
            <version>${swagger-models.version}</version>
        </dependency>
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>${swagger-annotations.version}</version>
        </dependency>
        <!--redis依賴配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--SpringSecurity依賴配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!--Hutool Java工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>
        <!--JWT(Json Web Token)登錄支持-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>${jjwt.version}</version>
        </dependency>
        <!--lombok依賴-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--SpringBoot配置處理-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <!--MyBatis Plus 依賴-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <!--MyBatis Plus 代碼生成器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <!--Velocity模板引擎-->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>${velocity.version}</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <!--表示執行任何子目錄下所有命名以Tests結尾的java類 -->
                    <includes>
                        <include>**/*Tests.java</include>
                    </includes>
                    <!--表示不執行任何子目錄下所有命名以Test開頭的java類 -->
                    <!--
                    <excludes>
                        <exclude>**/Test*.java</exclude>
                    </excludes>
                    -->
                </configuration>
            </plugin>
            <!-- docker-maven-plugin 插件就是為了幫助我們在Maven工程中,通過簡單的配置,自動生成鏡像並推送到倉庫中。
                微服務部署有兩種方法:
                (1)手動部署:首先基於源碼打包生成jar包(或war包),寫個Dockerfile文件,基於基礎鏡像搞個新鏡像,將jar包(或war包)上傳至虛擬機並拷貝至JDK容器。(太麻煩了)
                (2)通過Maven插件自動部署。 這也是企業實際開發中經常使用的方法。
                參考:
                https://blog.csdn.net/weixin_44424668/article/details/104062822
                https://www.cnblogs.com/jpfss/p/10945324.html
             -->
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>${docker.maven.plugin.version}</version>
                <executions>
                    <execution>
                        <id>build-image</id>
                        <phase>package</phase>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <!--修改imageName節點的內容,改為私有倉庫地址和端口,再加上鏡像id和TAG,我們要直接傳到私服-->
                    <!--配置最后生成的鏡像名,docker images里的,我們這邊取項目名:版本-->
                    <imageName>192.168.82.46:18083/${project.artifactId}:${project.version}</imageName>
                    <dockerHost>${docker.host}</dockerHost>
                    <!--基礎鏡像,相當於Dockerfile里的from-->
                    <baseImage>ascdc/jdk8</baseImage>
                    <!--入口點,project.build.finalName就是project標簽下的build標簽下的filename標簽內容,testDocker-->
                    <!--相當於啟動容器后,會自動執行java-jar/testDocker.jar-->
                    <entryPoint>["java", "-jar","/${project.build.finalName}.jar"]</entryPoint>
                    <!--是否推送到docker私有倉庫  設置為true 每次構建都要推送鏡像-->
                    <!--<pushImage>true</pushImage>-->
                    <!-- 要在$MAVEN_HOME/settings.xml中配置對應的serverId才行 否咋報錯Fail : no basic auth credentials -->
                    <serverId>cicd-docker-release</serverId>
                    <registryUrl>192.168.82.46:18083</registryUrl>
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <!--
                                把哪個文件上傳到docker,相當於Dockerfile里的add testDocker.jar
                                mvn clean,mvn install一下,先放到本地倉庫再說
                                mvn docker:build命令創建鏡像,如果還要上傳,加個-DpushImage參數
                                mvn clean package docker:build 只執行 build 操作
                                mvn clean package docker:build -DpushImage 執行 build 完成后 push 鏡像
                                mvn clean package docker:build -DpushImageTag 執行 build 並 push 指定 tag 的鏡像
                            -->
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
View Code

注意很坑的一個地方:

(2.1)pom.xml里一定不能配置跳過測試 否則target下不會生成surefire-reports目錄
<skipTests>false</skipTests>
(2.2)Junit測試類中@Test注解必須是org.junit.Test

(3)編寫pipeline

pipeline{
    agent any
    options {
        ansiColor('xterm')
    }
    stages{
        stage("單元測試"){
            steps {
                sh "mvn package -Dmaven.test.skip=false"
            }
        }
    }
    //將JUnit步驟放在post always中 當測試環境不通過時 依然可以收集到測試報告
    post{
        always{
            script{
                junit "**/target/surefire-reports/*.xml"
            }
        }
    }
}

查看測試報告:

參考:
Jenkins 集成單元測試報告
用插件MAVEN-SUREFIRE-REPORT-PLUGIN生成HTML格式測試報告

2、Jenkins集成JaCoCo檢查代碼覆蓋率

(1)安裝JaCoCo插件
(2)maven項目中引入jacoco插件

<plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.8.3</version>
                <configuration>
                    <skip>false</skip>
                    <destFile>target/coverage-reports/jacoco.exec</destFile>
                </configuration>
                <executions>
                    <execution>
                        <id>prepare-agent</id>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>report</id>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>post-unit-test</id>
                        <phase>test</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                        <configuration>
                            <!--jacoco執行數據的文件路徑-->
                            <dataFile>target/coverage-reports/jacoco.exec</dataFile>
                            <!--輸出報告路徑-->
                            <outputDirectory>target/coverage-reports</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

完整pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.macro.mall</groupId>
    <artifactId>mall-tiny</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <name>mall-tiny</name>
    <description>mall-tiny project</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <skipTests>false</skipTests>
        <!--該方法有漏洞,容易被黑客遠程放入挖礦機鏡像,開啟需做好防范,
        年少無知的我,開放2375,沒做ip限制,被拉去挖礦了。。。
        推薦使用CA加密端口-->
        <docker.host>http://192.168.118.106:2375</docker.host>
        <docker.maven.plugin.version>1.2.2</docker.maven.plugin.version>
        <druid.version>1.1.10</druid.version>
        <hutool.version>4.5.7</hutool.version>
        <swagger2.version>2.9.2</swagger2.version>
        <swagger-models.version>1.6.0</swagger-models.version>
        <swagger-annotations.version>1.6.0</swagger-annotations.version>
        <mysql-connector.version>8.0.16</mysql-connector.version>
        <jjwt.version>0.9.0</jjwt.version>
        <mybatis-plus.version>3.3.2</mybatis-plus.version>
        <velocity.version>2.2</velocity.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencies>
        <!--SpringBoot通用依賴模塊-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--SpringBoot校驗框架-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <!--集成druid連接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <!--Mysql數據庫驅動-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql-connector.version}</version>
        </dependency>
        <!--Swagger-UI API文檔生產工具-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${swagger2.version}</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${swagger2.version}</version>
        </dependency>
        <!--解決Swagger 2.9.2版本NumberFormatException-->
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
            <version>${swagger-models.version}</version>
        </dependency>
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>${swagger-annotations.version}</version>
        </dependency>
        <!--redis依賴配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--SpringSecurity依賴配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!--Hutool Java工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>
        <!--JWT(Json Web Token)登錄支持-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>${jjwt.version}</version>
        </dependency>
        <!--lombok依賴-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--SpringBoot配置處理-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <!--MyBatis Plus 依賴-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <!--MyBatis Plus 代碼生成器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <!--Velocity模板引擎-->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>${velocity.version}</version>
        </dependency>
        <!-- jacoco jar包引用 -->
        <dependency>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <version>0.8.3</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <!--表示執行任何子目錄下所有命名以Tests結尾的java類 -->
                    <includes>
                        <include>**/*Tests.java</include>
                    </includes>
                    <!--表示不執行任何子目錄下所有命名以Test開頭的java類 -->
                    <!--
                    <excludes>
                        <exclude>**/Test*.java</exclude>
                    </excludes>
                    -->
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.8.3</version>
                <configuration>
                    <skip>false</skip>
                    <destFile>target/coverage-reports/jacoco.exec</destFile>
                </configuration>
                <executions>
                    <execution>
                        <id>prepare-agent</id>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>report</id>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>post-unit-test</id>
                        <phase>test</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                        <configuration>
                            <!--jacoco執行數據的文件路徑-->
                            <dataFile>target/coverage-reports/jacoco.exec</dataFile>
                            <!--輸出報告路徑-->
                            <outputDirectory>target/coverage-reports</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <!-- docker-maven-plugin 插件就是為了幫助我們在Maven工程中,通過簡單的配置,自動生成鏡像並推送到倉庫中。
                微服務部署有兩種方法:
                (1)手動部署:首先基於源碼打包生成jar包(或war包),寫個Dockerfile文件,基於基礎鏡像搞個新鏡像,將jar包(或war包)上傳至虛擬機並拷貝至JDK容器。(太麻煩了)
                (2)通過Maven插件自動部署。 這也是企業實際開發中經常使用的方法。
                參考:
                https://blog.csdn.net/weixin_44424668/article/details/104062822
                https://www.cnblogs.com/jpfss/p/10945324.html
             -->
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>${docker.maven.plugin.version}</version>
                <executions>
                    <execution>
                        <id>build-image</id>
                        <phase>package</phase>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <!--修改imageName節點的內容,改為私有倉庫地址和端口,再加上鏡像id和TAG,我們要直接傳到私服-->
                    <!--配置最后生成的鏡像名,docker images里的,我們這邊取項目名:版本-->
                    <imageName>192.168.82.46:18083/${project.artifactId}:${project.version}</imageName>
                    <dockerHost>${docker.host}</dockerHost>
                    <!--基礎鏡像,相當於Dockerfile里的from-->
                    <baseImage>ascdc/jdk8</baseImage>
                    <!--入口點,project.build.finalName就是project標簽下的build標簽下的filename標簽內容,testDocker-->
                    <!--相當於啟動容器后,會自動執行java-jar/testDocker.jar-->
                    <entryPoint>["java", "-jar","/${project.build.finalName}.jar"]</entryPoint>
                    <!--是否推送到docker私有倉庫  設置為true 每次構建都要推送鏡像-->
                    <!--<pushImage>true</pushImage>-->
                    <!-- 要在$MAVEN_HOME/settings.xml中配置對應的serverId才行 否咋報錯Fail : no basic auth credentials -->
                    <serverId>cicd-docker-release</serverId>
                    <registryUrl>192.168.82.46:18083</registryUrl>
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <!--
                                把哪個文件上傳到docker,相當於Dockerfile里的add testDocker.jar
                                mvn clean,mvn install一下,先放到本地倉庫再說
                                mvn docker:build命令創建鏡像,如果還要上傳,加個-DpushImage參數
                                mvn clean package docker:build 只執行 build 操作
                                mvn clean package docker:build -DpushImage 執行 build 完成后 push 鏡像
                                mvn clean package docker:build -DpushImageTag 執行 build 並 push 指定 tag 的鏡像
                            -->
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
View Code

(3)編寫pipeline

 

pipeline{
    agent any
    options {
        ansiColor('xterm')
    }
    stages{
        stage("單元測試"){
            steps {
                sh "mvn clean install -Dmaven.test.skip=false"
                jacoco(
                        //代碼覆蓋率統計執行文件路徑 Ant風格路徑
                        execPattern: 'target/coverage-reports/jacoco.exec',
                        //class文件位置 Ant風格路徑
                        classPattern: 'target/classes',
                        //源代碼位置 Ant風格路徑
                        sourcePattern: 'src/main/java',
                        //排除分析的位置 Ant風格路徑
                        exclusionPattern: 'src/test*',
                        //是否禁用每行覆蓋率的源文件顯示
                        skipCopyOfSrcFiles: false,
                        //true則對各維度的覆蓋率進行比較 如果任何一個維度的當前覆蓋率小於最小覆蓋率閾值 則構建狀態為失敗;
                        //如果介於最大最小閾值之間則構建狀態為不穩定;如果大於最大閾值則構建成功
                        changeBuildStatus: true,
                        //字節碼指令覆蓋率
                        minimumInstructionCoverage: '30',
                        maximumInstructionCoverage: '70',
                        //行覆蓋率
                        minimumLineCoverage: '30',
                        maximumLineCoverage: '70',
                        //圈復雜度覆蓋率
                        minimumComplexityCoverage: '30',
                        maximumComplexityCoverage: '70',
                        //方法覆蓋率
                        minimumMethodCoverage: '30',
                        maximumMethodCoverage: '70',
                        //類覆蓋率
                        minimumClassCoverage: '30',
                        maximumClassCoverage: '70',
                        //分支覆蓋率
                        minimumBranchCoverage: '30',
                        maximumBranchCoverage: '70',
                        //如果為true 則只有所有維度的覆蓋率變化量的絕對值小於小於相應的變化量閾值時構建結果才成功
                        buildOverBuild: true,
                        //各個維度覆蓋率的變化量閾值
                        deltaInstructionCoverage: '80',
                        deltaLineCoverage: '80',
                        deltaComplexityCoverage: '80',
                        deltaMethodCoverage: '80',
                        deltaClassCoverage: '80',
                        deltaBranchCoverage: '80' )
            }
        }
    }
    //將JUnit步驟放在post always中 當測試環境不通過時 依然可以收集到測試報告
    post{
        always{
            script{
                junit "**/target/surefire-reports/*.xml"
            }
        }
    }

}

(4)構建並查看jaCoCo報告

構建失敗 也會展示這個報告:

 

參考:
Jacoco+Jenkins持續集成配置覆蓋率

二、性能測試
Taurus是一個開源的自動化框架,用於運行各種開源負載測試工具和功能測試工具,比如JMeter。Taurus關鍵特性:可以使用yaml或json來描述性能測試,符合test as code的理念;會根據選擇的性能測試類型自動下載相應工具。在Jenkins使用Taurus需要安裝插件Performance.

示例:使用Jenkins運行JMeter進行性能測試

(1)Jenkins安裝Performance插件,就可以使用bzt指令

(2)Jenkins搭建Python環境

基於Taurus的性能測試是基於Python的,使用之前請務必確認系統中已經安裝了Python環境。

(2.1)安裝python、pip(Python包管理工具)、virtualenv(Python中虛擬環境管理工具)
Performance檢測沒有Taurus會在Jenkins工程下面創建一個虛擬環境taurus-venv,然后里面自動安裝pip install bzt。

[root@node106 mall-tiny_master]# pwd
/data/.jenkins/workspace/mall-tiny_master
[root@node106 mall-tiny_master]# ll
total 72
-rw-r----- 1 root root   277 Sep 21 10:08 blaze_exist_jmeter_config.yml
drwxr-x--- 2 root root   276 Sep 21 10:08 images
-rw-r----- 1 root root   454 Sep 21 10:08 Jenkinsfile
-rw-r----- 1 root root 11349 Sep 21 10:08 LICENSE
-rw-r----- 1 root root 10070 Sep 21 10:08 mvnw
-rw-r----- 1 root root  6608 Sep 21 10:08 mvnw.cmd
-rw-r----- 1 root root 12640 Sep 21 10:08 pom.xml
-rw-r----- 1 root root 12453 Sep 21 10:08 README.md
drwxr-x--- 2 root root    27 Sep 21 10:08 sql
drwxr-x--- 4 root root    30 Sep 21 10:08 src
drwxr-x--- 4 root root    64 Sep 21 10:08 taurus-venv

參考:CentOS7下搭建Python3開發環境並創建虛擬環境

問題1:pip升級問題
You are using pip version 18.1, however version 20.2.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
解決方案:
python -m pip install --upgrade pip -i https://pypi.douban.com/simple

問題2:找不到安裝包問題
ERROR: Could not find a version that satisfies the requirement virtualenvwrapper (from versions: none)
ERROR: No matching distribution found for virtualenvwrapper

換一下鏡像源:/root/.pip/pip.conf

[global]
index-url = https://pypi.douban.com/simple

常見pip下載鏡像還有:

阿里:https://mirrors.aliyun.com/pypi/simple
中國科學技術大學:https://pypi.mirrors.ustc.edu.cn/simple

(2.2)jenkins 安裝Pyenv Pipeline插件,可以使用withPythonEnv(){}

(3)當前項目里新增Taurus配置文件
blaze_exist_jmeter_config.yml用於描述如何進行性能測試

execution:
  - scenario: simple
scenarios:
  simple:
 # SimpleTestPlan.jmx為測試計划 由jmeter工具生成       script: SimpleTestPlan.jmx
modules:
  jmeter:
    # 注意:下載文件必須使用.zip后綴
    download-link: http://mirrors.tuna.tsinghua.edu.cn/apache/jmeter/binaries/apache-jmeter-{version}.zip
    version: 5.2.1

使用Jmeter生成jmx文件,參考:JMeter教程 

(4)當前項目新增Jenkinsfile編寫pipeline

pipeline{
    agent any
    options {
        ansiColor('xterm')
    }
    stages{
        stage("單元測試"){
            steps {
                sh "mvn clean install -Dmaven.test.skip=false"
            }
        }
        stage("性能測試"){
            steps {
                // 可以指定bzt 而不是使用虛擬環境自己安裝的bzt
                //sh "/usr/local/python3/bin/bzt 'blaze_exist_jmeter_config.yml'"
                bzt params: 'blaze_exist_jmeter_config.yml'
            }
        }
    }
    //將JUnit步驟放在post always中 當測試環境不通過時 依然可以收集到測試報告
    post{
        always{
            script{
                junit "target/surefire-reports/*.xml"
                allure([
                        includeProperties: false,
                        jdk: '',
                        properties: [],
                        reportBuildPolicy: 'ALWAYS',
                        results: [[path: 'target/allure-results']]
                ])
            }
        }
    }

}

參考:利用Jenkins pipeline配置測試工具

記錄個問題:在虛擬環境目錄taurus-venv下沒有安裝成功bzt,一直報錯找不到bzt,懷疑是主機上python安裝的有問題,手工創建虛擬環境,並在虛擬環境下安裝bzt是沒問題的

基於這個問題,只好將安裝了一個全局bzt,並設置了環境變量/etc/profile中,主要需要重啟Jenkins:

(5)界面展示性能測試報告

三、輸出測試報告
Allure是一個非常美觀的測試報告生成器。
(1)安裝allure2-2.13.5.zip

(2)Jenkins配置allure安裝地址

(3)項目pom.xml中引入allure

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.macro.mall</groupId>
    <artifactId>mall-tiny</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <name>mall-tiny</name>
    <description>mall-tiny project</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <skipTests>false</skipTests>
        <!--該方法有漏洞,容易被黑客遠程放入挖礦機鏡像,開啟需做好防范,
        年少無知的我,開放2375,沒做ip限制,被拉去挖礦了。。。
        推薦使用CA加密端口-->
        <docker.host>http://192.168.118.106:2375</docker.host>
        <docker.maven.plugin.version>1.2.2</docker.maven.plugin.version>
        <druid.version>1.1.10</druid.version>
        <hutool.version>4.5.7</hutool.version>
        <swagger2.version>2.9.2</swagger2.version>
        <swagger-models.version>1.6.0</swagger-models.version>
        <swagger-annotations.version>1.6.0</swagger-annotations.version>
        <mysql-connector.version>8.0.16</mysql-connector.version>
        <jjwt.version>0.9.0</jjwt.version>
        <mybatis-plus.version>3.3.2</mybatis-plus.version>
        <velocity.version>2.2</velocity.version>
        <aspectj.version>1.8.10</aspectj.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencies>
        <!--SpringBoot通用依賴模塊-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--SpringBoot校驗框架-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <!--集成druid連接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <!--Mysql數據庫驅動-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql-connector.version}</version>
        </dependency>
        <!--Swagger-UI API文檔生產工具-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${swagger2.version}</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${swagger2.version}</version>
        </dependency>
        <!--解決Swagger 2.9.2版本NumberFormatException-->
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
            <version>${swagger-models.version}</version>
        </dependency>
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>${swagger-annotations.version}</version>
        </dependency>
        <!--redis依賴配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--SpringSecurity依賴配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!--Hutool Java工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>
        <!--JWT(Json Web Token)登錄支持-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>${jjwt.version}</version>
        </dependency>
        <!--lombok依賴-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--SpringBoot配置處理-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <!--MyBatis Plus 依賴-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <!--MyBatis Plus 代碼生成器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <!--Velocity模板引擎-->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>${velocity.version}</version>
        </dependency>
        <!-- jacoco jar包引用 -->
        <dependency>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <version>0.8.3</version>
        </dependency>
        <!-- allure包引用 -->
        <dependency>
            <groupId>io.qameta.allure</groupId>
            <artifactId>allure-junit4</artifactId>
            <version>2.12.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.20</version>
                <configuration>
                    <!--表示執行任何子目錄下所有命名以Test結尾的java類 -->
                    <includes>
                        <include>**/*Tests.java</include>
                    </includes>
                    <!--表示不執行任何子目錄下所有命名以Test開頭的java類 -->
                    <excludes>
                        <exclude>**/Test*.java</exclude>
                    </excludes>
                    <testFailureIgnore>false</testFailureIgnore>
                    <argLine>
                        -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
                    </argLine>
                    <properties>
                        <property>
                            <name>listener</name>
                            <value>io.qameta.allure.junit4.AllureJunit4</value>
                        </property>
                    </properties>
                    <systemProperties> 
                        <property>
                            <name>allure.results.directory</name>
                            <value>${project.build.directory}/allure-results</value>
                        </property>
                        <property>
                            <name>allure.link.issue.pattern</name>
                            <value>https://example.org.issue/{}</value>
                        </property>
                    </systemProperties>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjweaver</artifactId>
                        <version>${aspectj.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
            <plugin>
                <groupId>io.qameta.allure</groupId>
                <artifactId>allure-maven</artifactId>
                <version>2.8</version>
            </plugin>
            <!-- docker-maven-plugin 插件就是為了幫助我們在Maven工程中,通過簡單的配置,自動生成鏡像並推送到倉庫中。
                微服務部署有兩種方法:
                (1)手動部署:首先基於源碼打包生成jar包(或war包),寫個Dockerfile文件,基於基礎鏡像搞個新鏡像,將jar包(或war包)上傳至虛擬機並拷貝至JDK容器。(太麻煩了)
                (2)通過Maven插件自動部署。 這也是企業實際開發中經常使用的方法。
                參考:
                https://blog.csdn.net/weixin_44424668/article/details/104062822
                https://www.cnblogs.com/jpfss/p/10945324.html
             -->
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>${docker.maven.plugin.version}</version>
                <executions>
                    <execution>
                        <id>build-image</id>
                        <phase>package</phase>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <!--修改imageName節點的內容,改為私有倉庫地址和端口,再加上鏡像id和TAG,我們要直接傳到私服-->
                    <!--配置最后生成的鏡像名,docker images里的,我們這邊取項目名:版本-->
                    <imageName>192.168.82.46:18083/${project.artifactId}:${project.version}</imageName>
                    <dockerHost>${docker.host}</dockerHost>
                    <!--基礎鏡像,相當於Dockerfile里的from-->
                    <baseImage>ascdc/jdk8</baseImage>
                    <!--入口點,project.build.finalName就是project標簽下的build標簽下的filename標簽內容,testDocker-->
                    <!--相當於啟動容器后,會自動執行java-jar/testDocker.jar-->
                    <entryPoint>["java", "-jar","/${project.build.finalName}.jar"]</entryPoint>
                    <!--是否推送到docker私有倉庫  設置為true 每次構建都要推送鏡像-->
                    <!--<pushImage>true</pushImage>-->
                    <!-- 要在$MAVEN_HOME/settings.xml中配置對應的serverId才行 否咋報錯Fail : no basic auth credentials -->
                    <serverId>cicd-docker-release</serverId>
                    <registryUrl>192.168.82.46:18083</registryUrl>
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <!--
                                把哪個文件上傳到docker,相當於Dockerfile里的add testDocker.jar
                                mvn clean,mvn install一下,先放到本地倉庫再說
                                mvn docker:build命令創建鏡像,如果還要上傳,加個-DpushImage參數
                                mvn clean package docker:build 只執行 build 操作
                                mvn clean package docker:build -DpushImage 執行 build 完成后 push 鏡像
                                mvn clean package docker:build -DpushImageTag 執行 build 並 push 指定 tag 的鏡像
                            -->
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

 

(4)編寫pipeline

pipeline{
    agent any
    options {
        ansiColor('xterm')
    }
    stages{
        stage("單元測試"){
            steps {
                sh "mvn clean install -Dmaven.test.skip=false"
            }
        }
    }
    //將JUnit步驟放在post always中 當測試環境不通過時 依然可以收集到測試報告
    post{
        always{
            script{
                junit "target/surefire-reports/*.xml"
                allure([
                        includeProperties: false,
                        jdk: '',
                        properties: [],
                        reportBuildPolicy: 'ALWAYS',
                        results: [[path: 'target/allure-results']] ])
            }
        }
    }

}

(5)構建並查看測試allure報告

問題1:allure要展示測試報告,首先要有測試用例,使用Junit注解或者allure注解;然后就是要有前面的單元測試(Junit或者JaCoCo)、性能測試;最后將結果展示出來;
關於如何使用allure注解,可以參考:jenkins + Allure配置  

問題2:關於because the weaver option '-Xset:weaveJavaxPackages=true' has not been specified報錯的解決方案
解決方案:代理模式的aspectj 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM