功能+自動化測試代碼覆蓋率統計(jacoco-demo)


  • Jacoco 是一個開源的覆蓋率工具。Jacoco 可以嵌入到 Ant 、Maven 中,並提供了 EclEmma Eclipse 插件,也可以使用 Java Agent 技術監控 Java 程序。很多第三方的工具提供了對 Jacoco 的集成,如 sonar、Jenkins、IDEA。

  • Jacoco 包含了多種尺度的覆蓋率計數器,包含指令級(Instructions,C0 coverage),分支(Branches,C1 coverage)、圈復雜度(Cyclomatic Complexity)、行(Lines)、方法(Non-abstract Methods)、類(Classes)

 

這是對jacoco 的功能和使用的簡介,我就不需要過多的描述。我的這篇文章就是一個對docker中服務的一個功能測試+自動測試覆蓋率統計的demo:

我將從以下幾點進行闡述:

 

  1. docker 底層文件開放變量
  2. 自助式jenkins JOB創建
  3. Pipeline 自助式覆蓋率統計

一 docker 底層文件開放變量:

這里開放變量的作用是決定  自助式jenkins JOB  是否執行jacoco 覆蓋率代碼掃描。因為我們是通過jacocoAgent  這種方式來實現代碼覆蓋率掃描的。並不是所有的服務都需要

進行代碼覆蓋率掃描,所以我們做成了這種參數化,方便自助決定是否進行覆蓋率掃描。

你可能會有疑問為什么不寫死呢?答案是:我們的測試環境中的docker底層文件用的是同一套。

開放變量的參數是:-javaagent:/usr/local/jacoco-agent.jar=includes=*,output=tcpserver,append=true,address=0.0.0.0,port=*****

這里的這個參數傳遞是在 第二個環節自助式jenkins JOB 創建 中設置的一個輸入標簽

二 自助式jenkins JOB創建

前期可愛的運維同事,幫助我們創建了一個通用的自助構建服務的模板:

 

 

  1、jobName  <必填>選項,命名格式:環境-服務名

  2、service_name <必填>服務名稱,請對應gitlab上項目名稱和生成的jar包名稱

  3、app_repo <必填>項目倉庫地址,必須以git@開頭的ssh地址

  4、jvm_opts(開放變量) <可選填>自定義jvm參數,除默認配置jvm參數之外的自定義jvm參數,默認為空  這里由於我們需要運行jacoco-agent,所以輸入:-javaagent:/usr/local/jacoco-        agent.jar=includes=*,output=tcpserver,append=false,address=0.0.0.0,port=****

 

點擊build,會自動生成build后job的地址

 

點擊鏈接,自跳轉到job

 

 

 

 點擊build with parameters

 

如上圖所示  點擊build with parameters后  1、2、3會自動填上之前的參數,這里我們只需要選着4、5  部署的分支和部署環境就完成了自助式jenkins JOB創建。下面你就可以進行功能測試和自動化測試了。

接下來的重點是如何拉取代碼覆蓋率報告:

這里需要注意的是,jacocoAgent 記錄了代碼執行的軌跡,如果想通過**.exec 獲取html報告,我們需要有對應分支的.class 文件才可能實現。這里參照sonar掃描一樣的方式獲取

class文件。我們通過PipeLine的方式通過編譯對應分支的代碼獲取class文件。

三  Pipeline 自助式覆蓋率統計

這里的的工作主要是通過build   獲取class文件,通過.exec文件生成覆蓋率報告在jenkins上展示出來

那么是如何是實現的呢?

1、也需要運維像第一部一樣創建一個公共job  作用僅僅是build操作,而不需要deploy

2、需要在git上創建一個PipeLine公共腳本  PipleLine 開放幾個公共標簽

     標簽內容是:

  •        服務名稱service_name 
  •   務器地址address
  •   編譯后生成的classes文件相對路徑classPattern
  •     剔除無需統計具體的classes文件:exclusionPattern
  •     源碼路徑sourcePattern
  •   倉庫地址:app_repo

腳本如下:

 

pipelineJob("$jobName") {
  parameters {
    stringParam("service_name", "${service_name}",'服務名稱')
    stringParam('address', "${address}", '服務器地址')
      stringParam("classPattern", "${classPattern}", '編譯后生成的classes文件相對路徑')
    stringParam('exclusionPattern', "${exclusionPattern}", '剔除無需統計具體的classes文件,多個以英文逗號,隔開。')
    stringParam('sourcePattern', "${sourcePattern}", '源碼路徑。')
    stringParam('app_repo', "${app_repo}", '倉庫地址')

    
    gitParameter {
      name('branch_name')
      branch('')
      type('PT_BRANCH')
      defaultValue('master')
      description('')
      branchFilter('origin/(.*)')
      quickFilterEnabled(true)
        tagFilter('*')
      sortMode('ASCENDING_SMART')
      selectedValue('TOP')
      useRepository("$app_repo")
    }




    }

  definition {
    cpsScm {
    scm {
        git {
          remote {
            url('git@gitlab.***.cn:***/jenkinspipeline.git')
            credentials('*********************')
          }
          branch('*/master')
        }
      }
      scriptPath("Jenkinsfile-Jacoco")
    }
  }
}

 

 

jenkinspipeline  (git文件)

pipeline {
  agent {node {label 'k8s-slave'}}

  environment {
    def JAVA_HOME="/usr/local/jdk"
    def M2_HOME="/usr/local/maven"
    def MAVEN_OPTS="-Xmx1024m"

    def PATH="/opt/kube/bin:/bin:/sbin/:/usr/bin:/usr/sbin/:/usr/local/bin:$PATH"

    def dingding_url="https://oapi.dingtalk.com/robot/send?access_token=**************************"

    def harbor_server="***************"

    def harbor_auth_id="**********************"

    def git_auth_id="*********************"

    def ansible_repo="git@gitlab.*********************.git"

    def app_repo="git@gitlab.*********************.git"
    
  }

  options {
//默認是啟用並發構建,disableConcurrentBuilds如果開啟則為禁用並發構建
//    disableConcurrentBuilds()
    //保持構建的最大個數
    buildDiscarder(logRotator(numToKeepStr: '20'))
    ansiColor('xterm')
    timestamps()
  }
  
  parameters {
    choice(name: 'service_name', choices: '*********************')
    gitParameter(name: 'branch_name', branchFilter: 'origin/(.*)', defaultValue: 'master', type: 'PT_BRANCH', quickFilterEnabled: 'true', description: '選擇需要構建的分支', sortMode: 'ASCENDING_SMART')
  }

    post{
    success{
        script {

            dingTalk accessToken: "${env.dingding_url}", imageUrl: '*********************', jenkinsUrl: "${env.BUILD_URL}",message: "應用${service_name}構建成功!",notifyPeople: '*********************'

            wrap([$class: 'BuildUser']) {
                mail to: "${BUILD_USER_EMAIL}",
                from: "*********************",
                subject: "'${JOB_NAME}' 第${BUILD_NUMBER}次,構建結果通知【成功】",
                body: "本次構建由 ${BUILD_USER} 發起,構建【成功】,構建版本 ${params.service_name}:${params.branch_name} .\n具體構建細節,可以前往${env.BUILD_URL}進行查看。"
            }
 
        }

      cleanWs()

    }
    failure{
        script {

            dingTalk accessToken: "${env.dingding_url}", imageUrl: '*********************', jenkinsUrl: "${env.BUILD_URL}",message:"應用${service_name}構建失敗!",notifyPeople: '*********************'

            wrap([$class: 'BuildUser']) {
                mail to: "${BUILD_USER_EMAIL}",
                from: "*********************",
                subject: "'${JOB_NAME}' 第${BUILD_NUMBER}次,構建結果通知【失敗】",
                body: "本次構建由 ${BUILD_USER} 發起,構建【失敗】 ,構建版本 ${params.service_name}:${params.branch_name} .\n具體構建細節,可以前往${env.BUILD_URL}進行查看。"
            }
        }
    }
    unstable{
        script { 
            wrap([$class: 'BuildUser']) {
                mail to: "${BUILD_USER_EMAIL}",
                from: "*********************",
                subject: "'${JOB_NAME}' 第${BUILD_NUMBER}次,構建結果通知【失敗】",
                body: "本次構建由 ${BUILD_USER} 發起,構建【失敗】,構建版本 ${params.service_name}:${params.branch_name} .\n具體構建細節,可以前往${env.BUILD_URL}進行查看。"
            }
        }
    }
  }


  stages {
    stage("獲取代碼") {
      parallel{
        stage('配置構建信息') {
          steps {
            script {
              wrap([$class: 'BuildUser']){
                currentBuild.description = "本次構建由<strong><span style='color:#E53333;'> ${BUILD_USER} </span></strong>發起,構建版本 <strong><span style='color:#E53333;'>${params.service_name}:${params.branch_name}</span></strong>"
              }
            }
          }
        }


        stage("獲取應用代碼") {
          steps {
            echo "branch_name: ${params.branch_name}"
            sh 'git config --global http.sslVerify false'
            
            wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'xterm']) {
              dir ( "${env.WORKSPACE}" ) {
                git (
                  branch: "${params.branch_name}",
                  credentialsId: "${env.git_auth_id}",
                  url: "${app_repo}"
                )
              }
            }
          }
        }
        
      }
    }

    stage("jacoco覆蓋率統計") {
      steps {
        dir("${env.WORKSPACE}") {
            sh "pwd"
            sh "mvn clean install -Dmaven.test.skip=true org.jacoco:jacoco-maven-plugin:0.8.2:dump -Djacoco.address=\"${params.address}\" -Djacoco.port=********************* -Djacoco.destFile=jacoco_payment.exec -Djacoco.reset=false"
            jacoco(execPattern:'jacoco_payment.exec',classPattern:"${params.classPattern}",sourcePattern:"${params.sourcePattern}",exclusionPattern:"${params.exclusionPattern}")
                                   
        }  
      }
    }
  }
}

 

 上面的PipeLine 配置好了 下面 看看 頁面

 

 

注:第一次只能選擇master分支。后面可以選擇對應的分支了

 

 

 

 

 

 

好了  到此結束

 

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

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



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