代码改变世界

【Devops】【测试左移】jacoco代码覆盖率统计的几个脚本

2022-09-27 15:47  码上起舞  阅读(192)  评论(0编辑  收藏  举报
背景、
代码覆盖率统计,本来有更简单的方式,在mvn或者pom中加插件即可,but,历史代码历史工程太多,直接改pom需要工作量较大,要无感知集成代码覆盖率检查,故整理了这几个脚本来结合jenkins工程使用

一、在测试服务器部署路径下注入jacoco
insert.sh是用于将jacoco.sh中的内容打桩到catalina.sh的脚本中,需传一个参数,为服务器的ip地址。使用方式为sh insert.sh <server_ip>
#!/bin/bash
#该脚本用于将jacoco的代理内容(jacoco.sh)插入catalina.sh的启动脚本中
#使用方式:sh insert.sh 10.xx.xx.xx
#jacoco,默认使用9999端口的tcp方式
if [ $# -ne 1 ];then
 echo "Usage:$0 filename"
 exit 1
fi
#将ip写入jacoco.sh
ip=$1
sed -i "s/address=/&$ip/" jacoco.sh
#cat jacoco.sh
#将jacoco内容插入catalina.sh
jagent=`cat -n catalina.sh |grep -i "javaagent"`
echo $jagent
if [[ -z $jagent ]];then
    #在第一个java_opts变量定义的后面加入jacoco的代理内容
    row=`cat -n catalina.sh |grep -i "JAVA_OPTS="|awk '{print $1}'|sed -n "1"P`
    sed -i "${row}r jacoco.sh" catalina.sh
    echo "|||execute insert.sh finished"
else
    echo "|||jacoco agent is already insert in,no need to execute insert.sh"
fi


 

二、将第一步需要打桩的代码内容汇总到jacoco.sh中

jacoco.sh 是jacoco agent的打桩具体内容,address为空,动态写入,默认端口为9999

if [ "$1" = "start" ];then
        JAVA_COCO="-javaagent:jacocoagent.jar=includes=*,output=tcpserver,port=9999,address="
        JAVA_OPTS="$JAVA_OPTS $JAVA_COCO"
        echo $JAVA_OPTS
fi

三、在jenkins服务器执行jaco_exec并收集报告

jacoco_exec.sh

#!/bin/bash
#该脚本用于将生成jacoco.exec文件并生成xml报告
#jacoco.exec文件在当前jenkins工程的workspace下的jacoco_exec文件夹下
#初始目录均为$WORKSPACE,需传4个参数,ip地址+classes地址+src源码地址+工作空间地址
#使用方式:sh jacoco_exec.sh 10.xx.xx.xx workspace/code/ workspace/code/ workspace
#src和class地址会根据传参进行遍历,传工程code目录即可
#jacoco,默认使用9999端口的tcp方式
if [ $# -ne 4 ];then
 echo "Usage:$0 envip classes srcs workspace"
 exit 1
fi
server_ip=$1
classes_dir=$2
src_dir=$3
workspace=$4

if [ -f "$workspace/jacoco_exec/jacoco.exec" ];then
    rm -rf $workspace/jacoco_exec/jacoco.exec
fi
sleep 3
#遍历$2中所有的src目录和classes目录
class_arr=()
src_arr=()
#arr[${#arr[*]}]
#遍历src目录和classes目录
function read_dir(){
    for file in `ls $1` #注意此处这是两个反引号,表示运行系统命令
    do
        if [ -d $1"/"$file ];then
            if [[ $file = "target" ]];then             
                if [[ -d $1"/src" ]];then
                class_arr[${#class_arr[*]}]=$1"/target/classes/com"

                src_arr[${#src_arr[*]}]=$1"/src/main/java/"
                fi
            else
                read_dir $1"/"$file
            fi
        fi
    done
} 
read_dir $classes_dir
echo ${class_arr[*]}
echo ${src_arr[*]}

#生成jacoco.exec文件
java -jar /data/jacoco/jacoco/lib/jacococli.jar dump --address $server_ip --port 9999 --destfile $workspace/jacoco_exec/jacoco.exec
#生成xml报告用于丰声发消息
num=${#class_arr[@]}
num=`expr $num - 1`
#每个目录生成report.xml
reportlist=""
for i in $(seq 0 ${num}); do
    reportlist="$reportlist $workspace/report$i.xml"
    java -jar /data/jacoco/jacoco/lib/jacococli.jar report $workspace/jacoco_exec/jacoco.exec --classfiles ${class_arr[$i]} --sourcefiles ${src_arr[$i]} --xml $workspace/report$i.xml
done
#java -jar /data/jacoco/jacoco/lib/jacococli.jar report $workspace/jacoco_exec/jacoco.exec --classfiles $classes_dir --sourcefiles $src_dir --xml $workspace/report.xml

echo $reportlist
#返回覆盖率结果
covmessage=$(python3 /data/llm/git/gis-qrcts-core-mpc-qa/SF_Jenkins_scripts/script_for_jacoco/get_jacoco_coverity.py $reportlist)
echo $covmessage

 

四、解析报告中的覆盖率值脚本

get_jacoco_coverity.py 是解析覆盖率的xml文件,将总体的class和method覆盖率计算出来,用于发消息通知。使用方式为python3 get_jacoco_coverity.py report.xml
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
date:2021/3/15
description:
'''
import sys
try:
  import xml.etree.cElementTree as ET
except ImportError:
  import xml.etree.ElementTree as ET
import sys

class Jacoverty:
    def get_javacoco_coverity(self,filenames):
        '''获取jacoco的 xml文件覆盖率统计数据'''
        class_cov=class_total=class_miss=0
        method_cov=method_total=method_miss=0
        for filename in filenames:
            tree = ET.parse(filename)
            root = tree.getroot()

            for counter in root.findall("counter"):
                covtype = counter.get("type")
                if "CLASS" == covtype:
                    class_miss += int(counter.get("missed"))
                    class_cov += int(counter.get("covered"))
                if "METHOD" == covtype:
                    method_miss += int(counter.get("missed"))
                    method_cov += int(counter.get("covered"))
        class_total += class_miss + class_cov
        method_total += method_miss+method_cov
        class_coverty = format(float(class_cov)/float(class_total),'.0%')
        method_coverty = format(float(method_cov) / float(method_total), '.0%')
        # print(class_total,class_cov,method_total,method_cov)
        str = f'Coverage Summary = {"CLASS"}:{class_coverty};{"METHOD"}:{method_coverty};'
        print(str)
        return str

if __name__ == '__main__':
    files = sys.argv[1:]
    # files = ["reportxml2.xml","reportxml.xml"]
    Jacoverty().get_javacoco_coverity(files)

 
五、举例

jenkins工程使用示例

#拷贝jacoco包和脚本到bin目录
/usr/bin/scp -i ~/.ssh/id_rsa -P22 /data/script_for_jacoco/jacoco.sh /data/script_for_jacoco/insert.sh appdeploy@$server_ip:/data/server/bin
/usr/bin/scp -i ~/.ssh/id_rsa -P22 /data/jacoco/jacoco/lib/jacocoagent.jar appdeploy@$server_ip:/data/server/bin

sleep 100
#生成覆盖率文件
classes=${WORKSPACE}/code
srcs=${WORKSPACE}/code
source /data/script_for_jacoco/jacoco_exec.sh $server_ip $classes $srcs ${WORKSPACE}
echo $covmessage

#注释,如果不用上面封装的脚本,则用下面的一步一步执行,核心原理一样 #hostip
="xx.xx.xx.xx" #cd $WORKSPACE #if [ -f "./jacoco_exec/jacoco.exec" ];then # rm -rf ./jacoco_exec/jacoco.exec #fi #sleep 30 #java -jar /data/acoco/jacoco/lib/jacococli.jar dump --address $hostip --port 9999 --destfile ./jacoco_exec/jacoco.exec #java -jar /data/jacoco/jacoco/lib/jacococli.jar report ./jacoco_exec/jacoco.exec --classfiles ./code/databoard-boot/target/classes/com --sourcefiles ./code/databoard-boot/src/main/java/ --xml ./report.xml #cd /data/script_for_jacoco #ls #covmessage=$(python3 get_jacoco_coverity.py $WORKSPACE/report.xml) #pwd #ls