天天看点

Go服务自动触发单元测试覆盖率

一、用到的工具

  • Gitlab
  • Jenkins
  • Shell
  • go test

二、实现原理

在gitlab上配置jenkins的webhook,当有代码变更时自动触发jenkins构建job,job内的shell脚本负责把覆盖率报告以钉钉群通知的方法发送出去。

Go服务自动触发单元测试覆盖率

三、Jenkins job配置

Go服务自动触发单元测试覆盖率

点击上图中的“高级”,出现下图后,点击“Generate”,生成Secret token。

Go服务自动触发单元测试覆盖率

四、Gitlab配置webhook

Go服务自动触发单元测试覆盖率

五、Shell脚本

Go服务自动触发单元测试覆盖率

touch last_num.txt

fi

#存储本次.go文件和_test.go文件的个数,作为上次数据

echo $this_time_go_num > ./this_time_go_num.txt

echo $this_time_test_go_num > ./this_time_test_go_num.txt

echo $this_time_per > ./this_time_per.txt

#获取上次的.go文件数,如果没有则创建文件

if test -e last_time_go_num.txt

then

last_time_go_num=$(cat last_time_go_num.txt)

echo $last_time_go_num

else

touch last_time_go_num.txt

#获取上次的test.go文件数,如果没有则创建文件

if test -e last_time_test_go_num.txt

last_time_test_go_num=$(cat last_time_test_go_num.txt)

echo $last_time_test_go_num

touch last_time_test_go_num.txt

#获取上次的per,如果没有则创建文件

if test -e last_time_per.txt

last_time_per=$(cat last_time_per.txt)

echo $last_time_per

touch last_time_per.txt

#计算两次.go文件数的差

go_num_diff=`expr $this_time_go_num - $last_time_go_num`

echo $go_num_diff

#计算两次test.go文件数的差

test_go_num_diff=`expr $this_time_test_go_num - $last_time_test_go_num`

echo $test_go_num_diff

#计算两次占比的差

this_time_test_go_num_init=$(printf "%d" $(($this_time_test_go_num*100/$this_time_go_num)))

last_time_test_go_num_init=$(printf "%d" $(($last_time_test_go_num*100/$last_time_go_num)))

per_diff=$(printf "%d%%\n" $(($this_time_test_go_num_init-$last_time_test_go_num_init)))

echo $per_diff

cd -

echo "生成Html报告"

go tool cover -html=cover.out -o coverage.html

cp coverage.html /Users/xes/CI/reports/xxx-unitcover/a_this_time_html_report/this_time_coverage.html

# 构造知音楼通知text的内容

cd $this_path

this_time=$(cat this_num.txt)

last_time=$(cat last_num.txt)

now=$(echo $this_time|cut -b 1,2,3,4)

last=$(echo $last_time|cut -b 1,2,3,4)

change=$(echo | awk "{print $now - $last}")

# 设置secret

secret=""

# 设置Webhook

xxx_robot_path=

access_token=

# URL Encode 函数

function urlencode() {

local LANG=C

local length="${#1}"

i=0

while :

do

[ $length -gt $i ]&&{

local c="${1:$i:1}"

case $c in

[a-zA-Z0-9.~_-]) printf "$c" ;;

*) printf '%%%02X' "'$c" ;;

esac

}||break

let i++

done

}

# 执行函数

function run() {

# 获取时间戳

cur_sec_and_ns=`date '+%s-%N'`

cur_sec=${cur_sec_and_ns%-*}

cur_ns=${cur_sec_and_ns##*-}

cur_timestamp=$((cur_sec*1000+cur_ns/1000000))

echo "当前时间戳:"$cur_timestamp

# 获得签名

sign=`echo -n -e "$cur_timestamp\n$secret" | openssl dgst -sha256 -hmac $secret -binary | base64`

echo "加密后签名:"$sign

# 对签名进行 urlencode

sign_urlencode=`urlencode $sign`

echo "urlencode 后签名:"$sign_urlencode

url_action=""

url_encode=`urlencode $url_action`

echo $url_encode

request_url=$yach_robot_path"&timestamp="$cur_timestamp"&sign="$sign_urlencode

echo "最终请求的 URL:"$request_url

curl -X POST \

$request_url \

-H 'content-type: application/json' \

-d '{

"msgtype": "action_card",

"action_card": {

"title": "单测统计xxx",

"markdown": "### *_test.go占比(不含vendor) \n| 统计----------- | 本次------ | 上次------ | 新增 | \n| :--- | :--- | :--- | :--- | \n| .go | '"$this_time_go_num"' | '"$last_time_go_num"' | '"$go_num_diff"' | \n| test.go | '"$this_time_test_go_num"' | '"$last_time_test_go_num"' | '"$test_go_num_diff"' | \n| test.go/.go | '"$this_time_per"' | '"$last_time_per"' | '"$per_diff"' | \n### *_test.go覆盖率(平均值) \n| 本次------ | 上次------ | 差值 | \n| :--- | :--- | :--- | \n| '"$this_time"' | '"$last_time"'| '"$change"' | \n \n#### 本次&上次覆盖率HTML报告(点击打开) \n'"$url_action"'",

"image": "https://sentry.io/_assets/screenshots/features-page-dash-12c65431808e7d8daf234a096446c1f0da311a0f3bcec5352e28bda60136fb16.jpg",

"content_title": "xxx单测覆盖率统计",

"single_title": "点击此处,在侧边栏查看HTML报告",

"single_url": ""

}

}'

run

#把本次的覆盖率赋值给上次

cp this_num.txt last_num.txt

#把本次的.go文件值给上次

cp this_time_go_num.txt last_time_go_num.txt

#把本次的test.go文件值给上次

cp this_time_test_go_num.txt last_time_test_go_num.txt

#把本次的per值给上次

cp this_time_per.txt last_time_per.txt

#用本次的HTML报告覆盖上次的HTML报告

cd ..

cp a_this_time_html_report/this_time_coverage.html b_last_time_html_report/last_time_coverage.html

避坑:

在slave机器上git clone遇到一个小坑,如下图:

Go服务自动触发单元测试覆盖率

原因是slave机器上的git默认账号对此gitlab仓库权限不足,解决方法是给git clone命令加上username和password

Go服务自动触发单元测试覆盖率

六、Go test 命令

如步骤五中所示,用到2个go test命令,如下:

go test ./... -coverprofile=cover.out                               # 生成.out文件

go tool cover -html=cover.out -o coverage.html        # 生成Html报告

七、钉钉群通知

钉钉机器人配置:

钉钉机器人的安全设置方式有3种,我们这里选择方式一“自定义关键词”

Go服务自动触发单元测试覆盖率

添加钉钉机器人:

Go服务自动触发单元测试覆盖率

请求字段说明:

Go服务自动触发单元测试覆盖率

注意:请求的content中(content即link的值,也就是在text或title中包含)必须包含钉钉机器人的“自定义关键词”,比如我们curl请求中就包含了“单元测试”,否则会报如下图的错误

Go服务自动触发单元测试覆盖率

八、通知消息展示

钉钉群接收到的通知消息:

Go服务自动触发单元测试覆盖率

继续阅读