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.

Alibaba Cloud Developer
Alibaba Cloud Developer
Alibaba Cloud Developer
How to Build an Automated Go Unit Test & Coverage Pipeline with Java Service

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

Test execution flowchart
Test execution flowchart

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/profile

Install 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-xml

Install 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/simple

Install 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/
 fi

3. 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 success

4. 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
done

5. Final Results

The final output shows unit‑test results, incremental line coverage, and overall line coverage, accessible via Nginx static file serving.

AONE test run example
AONE test run example
Case pass/fail
Case pass/fail
Incremental coverage
Incremental coverage
Line coverage
Line coverage
code coverageGounit testingAone
Alibaba Cloud Developer
Written by

Alibaba Cloud Developer

Alibaba's official tech channel, featuring all of its technology innovations.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.