How to Build an Automated Go Unit Test & Coverage Pipeline with Java Service
This article describes how to set up a low‑maintenance, automated unit‑test and integration‑test environment for Go applications using a Java service in a pre‑integration platform, covering Docker packaging, Go tool installation, coverage plugins, diff‑cover for incremental coverage, and REST APIs for task management.
Background
Most of the Gaode ride‑hailing services are developed in Go. We want the pre‑integration environment to automatically trigger unit tests and API automation tests after code deployment, and generate coverage reports with line‑incremental data and test logs.
Unit Testing
1. Overview of Test Execution
The AONE digital R&D platform provides integration‑test labs that can run custom scripts. The unit‑test flow is: the lab script triggers a Java service, which runs the Go test script, and the lab polls for results. Directly running tests in the lab is avoided because the lab does not support custom Docker images and each application may have different test commands.
When developers push code and deployment finishes, the lab automatically calls /unit/taskReceive to dispatch the test task.
Because the test script may run long, the lab repeatedly calls /unit/taskQuery until the task finishes.
When the script completes, it calls /unit/taskSave to store the result, which the lab then displays.
The lab parses and shows the test outcome.
2. Environment Setup
Package the required environment into the Java service Docker image:
Install Go.
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\"
export GOPATH=\"/${your_go_path_dir}/gopath\"
export GOPROXY=\"${go_proxy},direct\"" >> /etc/profile
source /etc/profileInstall coverage plugins (gocov-html, gocov, gocov-xml).
go get github.com/matm/gocov-html
go get github.com/axw/gocov/...
go get github.com/AlekSi/gocov-xmlInstall diff‑cover for incremental coverage (requires Python 3 and build tools).
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/simpleInstall and configure Git with SSH keys for code checkout.
yum -y install git
name=`git config user.name`
if [ -z "$name" ]; then
git config --global user.name "xxx"
git config --global user.email "[email protected]"
mkdir -p ~/.ssh
cp ${your_id_rsa} ~/.ssh/
fi3. Java Service Implementation
Task Dispatch API
Path: /unit/taskReceive
Method: POST
Params: {"taskId":"123456","appName":"AppA","branch":"releases/test-branch-code","repo":"[email protected]"}
Result: (any response, will timeout)Implementation stores the task status in Redis, selects the appropriate ${appName}.sh script (downloaded from OSS if missing), runs the script, collects coverage files, generates HTML reports, and posts results to /unit/taskSave.
#!/bin/bash
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
# clone code
cd $DIR/$APP_NAME/$TaskId
git clone -b $Branch $Repo
# run tests
cd ./$APP_NAME
go test ./... -timeout 3m -v -cover=true -coverprofile=$COVER_FILE -mod=vendor -args --confDir=$CONF_DIR >> $LOG_FILE
# generate coverage reports
gocov convert $COVER_FILE | gocov-xml > $DIR/$APP_NAME/$TaskId/cover/coverage.xml
diff-cover $DIR/$APP_NAME/$TaskId/cover/coverage.xml --compare-branch=origin/master --html-report $DIR/$APP_NAME/$TaskId/cover/report.html > $DIR/$APP_NAME/$TaskId/cover/diff.out
# extract metrics and upload
curl -i "http://$SERVER_HOST/unit/taskSave" -H "Content-Type:application/json" -X POST -d '{"taskId":"'$TaskId'","appName":"'$APP_NAME'","branch":"'$Branch'","taskRes":"{...}"}'Task Query API
Path: /unit/taskQuery
Method: POST
Params: {"taskId":"123456","appName":"xxxx"}
Result: code="1" with data when finished; code="2" with "task ongoing" otherwise.Task Save API
Path: /unit/taskSave
Method: POST
Params: {"taskId":"123456","appName":"xxxx","taskRes":"{...}"}
Result: code="1" on success4. Lab Configuration
TASK_ID=$(date "+%Y%m%d%H%M%S")
APP_NAME=xxxx
PREFIX=${APP_NAME}${TASK_ID}
curl -i "http://$SERVER_HOST/unit/taskReceive" -X POST -H "Content-Type:application/json" -d '{"taskId":"'$TASK_ID'","appName":"'$APP_NAME'","branch":"'$branch'","repo":"'$repo'"}'
# polling loop
for time in 10s 30s 40s 50s 70s 100s; do
res=$(curl "http://$SERVER_HOST/unit/taskQuery" -X POST -H "Content-Type:application/json" -d '{"taskId":"'$TASK_ID'","appName":"'$APP_NAME'"}')
# parse result and break when finished
sleep $time
done5. Final Results
The final output shows unit‑test results, incremental line coverage, and overall line coverage, accessible via Nginx static file serving.
Alibaba Cloud Developer
Alibaba's official tech channel, featuring all of its technology innovations.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
