自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Go應(yīng)用單元測(cè)試實(shí)踐

原創(chuàng) 精選
開發(fā) 前端
單元測(cè)試由aone實(shí)驗(yàn)室腳本觸發(fā),Java服務(wù)收到單測(cè)任務(wù)后調(diào)起單測(cè)腳本并執(zhí)行,最后由aone實(shí)驗(yàn)室輪詢運(yùn)行結(jié)果。

一、背景

高德打車運(yùn)營的應(yīng)用大多基于go進(jìn)行開發(fā)的,我們希望在預(yù)集成環(huán)境下,當(dāng)研發(fā)部署完代碼,能自動(dòng)觸發(fā)單元測(cè)試和接口自動(dòng)化測(cè)試,并生成覆蓋率報(bào)告。參考了許多篇關(guān)于go單元測(cè)試的文章,有的缺少行增量覆蓋率,有的缺少case運(yùn)行結(jié)果/case運(yùn)行日志。

本文旨在搭建一個(gè)穩(wěn)定運(yùn)行且維護(hù)成本低的單元測(cè)試/集成測(cè)試環(huán)境。

二、單元測(cè)試

1.單測(cè)運(yùn)行概述

圖1 單測(cè)運(yùn)行流程圖

aone作為阿里巴巴集團(tuán)數(shù)字化研發(fā)協(xié)同平臺(tái),本身提供了各種集成測(cè)試實(shí)驗(yàn)室,實(shí)驗(yàn)室中可以運(yùn)行自定義腳本。如圖1所示,為單元測(cè)試運(yùn)行流程圖。單元測(cè)試由aone實(shí)驗(yàn)室腳本觸發(fā),Java服務(wù)收到單測(cè)任務(wù)后調(diào)起單測(cè)腳本并執(zhí)行,最后由aone實(shí)驗(yàn)室輪詢運(yùn)行結(jié)果。之所以不在單測(cè)實(shí)驗(yàn)室腳本中直接運(yùn)行單測(cè),主要存在以下兩個(gè)原因。一是單測(cè)的運(yùn)行依賴GO環(huán)境,以及一些生成覆蓋率文件所需的三方工具。目前aone實(shí)驗(yàn)室不支持自定義鏡像接入,每次運(yùn)行都需要安裝環(huán)境,安裝環(huán)境的耗時(shí)遠(yuǎn)大于運(yùn)行單測(cè)。二是每個(gè)應(yīng)用的單測(cè)運(yùn)行命令可能不太一樣,一旦應(yīng)用數(shù)目較多,如果單測(cè)腳本需要調(diào)整,更改的成本比較高。因此啟動(dòng)一個(gè)JAVA服務(wù)(完全可以復(fù)用已有的服務(wù),降低成本),將運(yùn)行單測(cè)所需要的腳本,以及環(huán)境都打包在這個(gè)服務(wù)上。aone上的實(shí)驗(yàn)室腳本,只進(jìn)行單測(cè)任務(wù)的下發(fā)、輪詢和運(yùn)行結(jié)果的展示。具體流程如下:

  • 當(dāng)開發(fā)在預(yù)集成環(huán)境提交代碼、部署完成之后,流程自動(dòng)運(yùn)行單測(cè)實(shí)驗(yàn)室。單測(cè)實(shí)驗(yàn)室里的腳本,先調(diào)用任務(wù)下發(fā)接口/unit/taskReceive,這時(shí)Java服務(wù)會(huì)調(diào)用對(duì)應(yīng)的單測(cè)腳本。
  • 由于單測(cè)腳本運(yùn)行時(shí)間會(huì)比較長,所以/unit/taskReceive接口會(huì)超時(shí)。在單測(cè)腳本正在運(yùn)行的時(shí)候,單測(cè)實(shí)驗(yàn)室的腳本會(huì)一直調(diào)用/unit/taskQuery接口,查詢此次單測(cè)任務(wù)的狀態(tài),直到返回正確結(jié)果為止。
  • 當(dāng)單測(cè)腳本完成時(shí),會(huì)回調(diào)任務(wù)完成接口/unit/taskSave接口,將結(jié)果存起來。這樣單測(cè)實(shí)驗(yàn)室腳本再調(diào)用/unit/taskQuery接口查詢時(shí),就會(huì)返回此次單測(cè)的結(jié)果。
  • 單測(cè)實(shí)驗(yàn)室腳本,根據(jù)任務(wù)返回的結(jié)果,將單測(cè)結(jié)果解析、展示。

2.環(huán)境搭建

將所需的環(huán)境,打包到Java服務(wù)的docker中:

  • golang安裝

go單測(cè)需要運(yùn)行g(shù)o test,所以需要在環(huán)境中安裝go。安裝完成后,配置環(huán)境變量和代理。

wget https://golang.google.cn/dl/go1.17.8.linux-amd64.tar.gz
tar -zxvf go1.17.8.linux-amd64.tar.gz -C /usr/local/
mkdir -p /${your go path dir}/gopath
echo -e "export PATH=\"$PATH:/usr/local/go/bin:/${your go path dir}/gopath/bin\"\nexport GOPATH=\"/${your go path dir}/gopath\"\nexport GOPROXY=\"${go代理地址},direct\"" >> /etc/profile
source /etc/profile
  • 代碼覆蓋率插件安裝

運(yùn)用一些開源工具,將單測(cè)生成的覆蓋文件轉(zhuǎn)換成xml/html格式的覆蓋率文件。主要用到gocov-html,gocov,gocov-xml。參考地址[1][2]。

go get github.com/matm/gocov-html
go get github.com/axw/gocov/...
go get github.com/AlekSi/gocov-xml
  • 行增量覆蓋率工具安裝

利用diff-cover[3],生成行增量覆蓋率。diff-cover依賴python3,python3的安裝可能需要先裝好gcc,automake,autoconf,libtool,make,zlib,zlib-devel openssl。

yum -y install gcc automake autoconf libtool make zlib zlib-devel openssl openssl-devel
wget https://www.python.org/ftp/python/3.8.1/Python-3.8.1.tgz
tar -zxvf Python-3.8.1.tgz && cd Python-3.8.1 && ./configure && make && make install
pip3 install diff-cover -i https://mirrors.aliyun.com/pypi/simpl
  • git安裝&配置

運(yùn)行單元測(cè)試時(shí),依賴開發(fā)的代碼。需要配置好一個(gè)有代碼權(quán)限的git ssh公鑰和私鑰,用來下載代碼。

yum -y git 
name=`git config user.name`
if [ -z "$name" ]
then
git config --global user.name "xxx"
git config --global user.email "xxxx@xxxx.xxxx.com"
mkdir -p ~/.ssh
cp ${your id_rsa} ~/.ssh/
fi

3.Java服務(wù)實(shí)現(xiàn)

單測(cè)任務(wù)下發(fā)接口

Path:/unit/taskReceive

Method:POST

Params:{
"taskId": "123456", //可以用日期20220221102104,主要用來標(biāo)識(shí)此次單測(cè)
"appName":"應(yīng)用A", //應(yīng)用名,根據(jù)應(yīng)用名,選擇運(yùn)行對(duì)應(yīng)的單測(cè)腳本。比如應(yīng)用A就會(huì)運(yùn)行應(yīng)用A.sh
"branch":"releases/test-branch-code", //需要運(yùn)行單測(cè)的分支名
"repo":"git@xxxxx.git" //應(yīng)用A的代碼地址,下載代碼之后,才能運(yùn)行單測(cè)
}

Result:返回啥都行,反正會(huì)超時(shí)。

具體實(shí)現(xiàn)邏輯:

  • 在redis中記錄此次單測(cè)任務(wù),key:"${appName}${taskId}-unit",value:"ongoing"。以便/unit/taskQuery查詢,從而知道單測(cè)還在運(yùn)行中。
  • 根據(jù)appName參數(shù),選擇執(zhí)行${appName}.sh腳本。如果腳本不存在,就去阿里云對(duì)象存儲(chǔ)服務(wù)(Object Storage Service,簡(jiǎn)稱OSS)下載腳本(所以,如果單測(cè)腳本有更新,就更新下OSS上的腳本,然后刪除運(yùn)行機(jī)器上的${appName}.sh即可。這樣可以不重新部署Java服務(wù),即可更改運(yùn)行腳本)。${appName}.sh腳本大致邏輯如下:
source /etc/profile

APP_NAME=$1
Branch=$2
TaskId=$3
Repo=$4
DIR=`pwd`
PREFIX=$APP_NAME$TaskId

#生成覆蓋率文件的文件夾
mkdir -p $DIR/$APP_NAME/$TaskId/cover
COVER_FILE=$DIR/$APP_NAME/$TaskId/cover/core.cover
LOG_FILE=$DIR/$APP_NAME/$TaskId/cover/log.txt
COVER_DIR=$DIR/$APP_NAME/$TaskId/cover
UNIT_TEST_RESULT_FILE=$DIR/$APP_NAME/$TaskId/cover/unit_pass.txt

#存放覆蓋率詳情html文件的文件夾
mkdir -p /${your path}/res_unit

#下載代碼
cd $DIR/$APP_NAME/$TaskId
git clone -b $Branch $Repo

#運(yùn)行單元測(cè)試
cd ./$APP_NAME
CONF_DIR=$DIR/$APP_NAME/$TaskId/$APP_NAME/conf
go test ./... -timeout 3m -v -gcflags=-l -cover=true -coverprofile=$COVER_FILE -mod=vendor -args --confDir=$CONF_DIR >> $LOG_FILE

#行增量覆蓋率
gocov convert $COVER_FILE | gocov-xml > $COVER_DIR/coverage.xml
diff-cover $COVER_DIR/coverage.xml --compare-branch=origin/master --html-report $COVER_DIR/report.html > $COVER_DIR/diff.out
tmp=`cat $COVER_DIR/diff.out | grep "Total:" | cut -d ':' -f2`
if [ -n "$tmp" ]
then
echo "CODE_COVERAGE_NAME_UPDATELINES : 行增量"
CODE_COVERAGE_UPDATE_LINES_TOTAL=`cat $COVER_DIR/diff.out | grep "Total:" | cut -d':' -f2 | grep -o -E '[0-9]+'`
miss=`cat $COVER_DIR/diff.out | grep "Missing:" | cut -d ':' -f2 | grep -o -E '[0-9]+'`
CODE_COVERAGE_UPDATE_LINES_COVER=$(( CODE_COVERAGE_UPDATE_LINES_TOTAL - miss))
fi
cp $COVER_DIR/report.html /${your path}/res_unit/${PREFIX}update.html

#代碼行覆蓋率
gocov convert $COVER_FILE | gocov-html > $COVER_DIR/line.html
CODE_COVERAGE_LINES_COVER=`head -n 50 $COVER_DIR/coverage.xml | grep "lines-valid" | awk -F 'lines-covered' '{print $2}' | awk -F ' ' '{print $1}' | grep -o -E '[0-9]+'`
CODE_COVERAGE_LINES_TOTAL=`head -n 50 $COVER_DIR/coverage.xml | grep "lines-valid" | awk -F 'lines-valid' '{print $2}' | awk -F ' ' '{print $1}' | grep -o -E '[0-9]+'`
cp $COVER_DIR/line.html /${your path}/res_unit/${PREFIX}line.html

#case 通過情況
pass=`cat $LOG_FILE | grep -o "\--- PASS: " | wc -l`
fail=`cat $LOG_FILE | grep -o "\--- FAIL: " | wc -l`
echo "************************************" >> $UNIT_TEST_RESULT_FILE
cat $LOG_FILE | grep "\--- FAIL: " >> $UNIT_TEST_RESULT_FILE
echo "************************************" >> $UNITTEST_RESULT_FILE
echo "SUCCESS:" >> $UNIT_TEST_RESULT_FILE
cat $LOG_FILE | grep "\--- PASS: " >> $UNIT_TEST_RESULT_FILE
echo "************************************" >> $UNIT_TEST_RESULT_FILE
iconv -f UTF-8 -t gbk $UNIT_TEST_RESULT_FILE > temp.txt
sed -i 's/ //g;s/---//g' temp.txt
cat temp.txt > $UNIT_TEST_RESULT_FILE
cp $UNIT_TEST_RESULT_FILE /${your path}/res_unit/${PREFIX}pass.txt

#結(jié)果收集
curl -i "http://${your server host}/unit/taskSave" -H "Content-Type:application/json" -X POST -d "{\"taskId\":\"$TaskId\", \"appName\":\"$APP_NAME\", \"branch\": \"$Branch\", \"taskRes\": \"{\\\"code_coverage_update_lines_total\\\":$CODE_COVERAGE_UPDATE_LINES_TOTAL, \\\"code_coverage_update_lines_cover\\\":$CODE_COVERAGE_UPDATE_LINES_COVER,\\\"code_coverage_lines_total\\\":$CODE_COVERAGE_LINES_TOTAL, \\\"code_coverage_lines_cover\\\":$CODE_COVERAGE_LINES_COVER, \\\"fail\\\":$fail, \\\"pass\\\":$pass}\"}"

單測(cè)任務(wù)查詢接口

PATH:/unit/taskQuery

METHOD:POST

Params:{
"taskId": "123456", //可以用日期20220221102104,主要用來標(biāo)識(shí)此次單測(cè)
"appName":"xxxx", //應(yīng)用名,根據(jù)應(yīng)用名,選擇運(yùn)行對(duì)應(yīng)的單測(cè)腳本
}

Result:如果單測(cè)運(yùn)行完成,返回code="1",data是單測(cè)結(jié)果。如果單測(cè)沒完成,返回code="2",data="task ongoing",如果單測(cè)運(yùn)行超過10分鐘,返回code="2",data="redis nil or delay"

單測(cè)結(jié)果保存接口

PATH:/unit/taskSave

METHOD:POST

Params:{
"taskId": "123456", //可以用日期20220221102104,主要用來標(biāo)識(shí)此次單測(cè)
"appName":"xxxx", //應(yīng)用名,根據(jù)應(yīng)用名,選擇運(yùn)行對(duì)應(yīng)的單測(cè)腳本。
"taskRes":"{\"code_coverage_update_lines_total\":100,\"code_coverage_update_lines_cover\":100,\"code_coverage_lines_cover\":100,\"code_coverage_lines_total\":100,\"fail\":0,\"pass\":100}" //單測(cè)運(yùn)行結(jié)果
}

Result:成功返回code="1"

4.實(shí)驗(yàn)室配置

如1.1所述,aone實(shí)驗(yàn)室只需要分發(fā)任務(wù)、輪詢?nèi)蝿?wù),以及解析結(jié)果。

TASK_ID=$(date "+%Y%m%d%H%M%S")
APP_NAME=`xxxx`
PREFIX=$APP_NAME$TASK_ID

echo $TASK_ID
echo $APP_NAME
echo $PREFIX

failed="true"
# 分發(fā)任務(wù)
curl -i "http://${your server host}/unit/taskReceive" -X POST -H "Content-Type:application/json" -d "{\"taskId\": \"$TASK_ID\",\"appName\": \"$APP_NAME\", \"branch\": \"${branch}\", \"repo\":\"${repo}\"}"
for time in 10s 30s 40s 50s 70s 100s 100s 70s 50s 40s 30s 10s
do
#輪詢?nèi)蝿?wù)
res=$(curl "http://${your server host}/unit/taskQuery" -X POST -H "Content-Type:application/json" -d "{\"taskId\": \"$TASK_ID\",\"appName\": \"$APP_NAME\", \"branch\": \"${branch}\", \"repo\":\"${repo}\"}")
echo $res
code=$(echo $res | grep -o -E 'code":[0-9]' | cut -d ":" -f2)
isOngoing=$(echo $res | grep -o -E 'data":[^}]*' | cut -d ":" -f2)
if [ "$code" = "1" ] && [ $isOngoing != "\"ongoing\"" ] && [ $isOngoing != "null" ]
then
#根據(jù)res解析單元測(cè)試運(yùn)行結(jié)果
#略
break
fi
sleep $time
done

if [ "$failed" == "true" ]
then
echo "Job failed"
fi

5.最終結(jié)果

最終的運(yùn)行結(jié)果如圖2,單元測(cè)試、行增量覆蓋率、行覆蓋率都可以點(diǎn)擊跳轉(zhuǎn)查看詳情。如圖3,4,5。跳轉(zhuǎn)地址的實(shí)現(xiàn),是采用nginx提供的訪問靜態(tài)文件功能。只需要在nginx的配置文件中,增加配置。

location ^~ /res_unit {
root /${your path};
}

這樣,如果想訪問a.html文件,只需要將其放在/${your path}/res_unit/a.html。就可以通過鏈接https://${your server host}/res_unit/a.html訪問到。

圖2 aone單測(cè)運(yùn)行示例

圖3 case通過情況

圖4 行增量覆蓋率

圖5 行覆蓋率

三、其他

招聘高德共享出行技術(shù)質(zhì)量團(tuán)隊(duì)求賢若渴(北京崗),誠招Java開發(fā)P6&P7、測(cè)試開發(fā)工程師P6&P7。

參考鏈接:

[1]https://github.com/axw/gocov

[2]https://github.com/AlekSi/gocov-xml

[3]https://github.com/Bachmann1234/diff_cover

責(zé)任編輯:武曉燕 來源: 阿里開發(fā)者
相關(guān)推薦

2017-02-21 10:30:17

Android單元測(cè)試研究與實(shí)踐

2017-01-14 23:42:49

單元測(cè)試框架軟件測(cè)試

2024-10-07 09:12:33

2024-01-09 08:08:12

Go單元測(cè)試系統(tǒng)

2011-11-18 15:18:41

Junit單元測(cè)試Java

2017-01-14 23:26:17

單元測(cè)試JUnit測(cè)試

2017-01-16 12:12:29

單元測(cè)試JUnit

2020-08-18 08:10:02

單元測(cè)試Java

2022-08-05 09:30:57

單元測(cè)試C++

2024-08-15 08:11:10

2012-10-29 09:45:52

單元測(cè)試軟件測(cè)試測(cè)試實(shí)踐

2017-03-23 16:02:10

Mock技術(shù)單元測(cè)試

2021-05-05 11:38:40

TestNGPowerMock單元測(cè)試

2023-07-26 08:58:45

Golang單元測(cè)試

2011-07-04 18:16:42

單元測(cè)試

2020-05-07 17:30:49

開發(fā)iOS技術(shù)

2010-08-27 09:11:27

Python單元測(cè)試

2023-11-25 09:41:34

GogRPCHandler

2023-10-28 10:10:41

2011-05-16 16:52:09

單元測(cè)試徹底測(cè)試
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)