本篇文章展示了怎么写Unit Test及怎么统计coverage, 为了方便写UT,最好exposed Api is Method not function,为了更好的帮助大家理解,给出了一个例子方便大家参考。例子分为三部分,source code, unit test code, Makefile.
Code 目录
mkdir -p ~/test/src/gounit/etcd
source code
package etcd
import (
"context"
"log"
"time"
"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
"go.etcd.io/etcd/clientv3"
)
type KV interface {
Put(ctx context.Context, key, valstring, opts ...clientv3.OpOption) (*clientv3.PutResponse, error)
}
type etcdClient struct {
kv KV
}
const (
DefaultOperationTimeout =3 * time.Second
)
var (
endpoints = []string{"localhost:2379"}
)
func (ec *etcdClient) Put(ctx context.Context, key, val string, opts ...clientv3.OpOption) (*clientv3.PutResponse, error) {
ctx, cancel := context.WithTimeout(ctx, DefaultOperationTimeout)
resp, err := ec.kv.Put(ctx, key, val, opts...)
cancel()
if err != nil {
switch err {
case context.Canceled:
log.Printf("[ETCD] ctx is canceled by another routine: %v", err)
case context.DeadlineExceeded:
log.Printf("[ETCD] ctx is attached with a deadline is exceeded: %v", err)
case rpctypes.ErrEmptyKey:
log.Printf("[ETCD] client-side error: %v", err)
default:
log.Printf("[ETCD] bad cluster endpoints, which are not etcd servers: %v", err)
}
}
return resp, err
}
Unit Test code
package etcd
import (
"context"
"errors"
"testing"
"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
"github.com/stretchr/testify/assert"
"go.etcd.io/etcd/clientv3"
)
type mockEtcdClient struct {
}
var (
defaultErr = errors.New("default err")
)
func (mec *mockEtcdClient) Put(ctx context.Context, key, val string, opts ...clientv3.OpOption) (*clientv3.PutResponse, error) {
switch key {
case "canceled":
return nil, context.Canceled
case "deadline_exceeded":
return nil, context.
case "err_empty_key":
return nil, rpctypes.ErrEmptyKey
case "default":
return nil, defaultErr
default:
return nil, nil
}
}
type putResult struct {
putResponse *clientv3.PutResponse
err error
}
func TestPut(t *testing.T) {
api := &etcdClient{kv: &mockEtcdClient{}}
tests := []struct {
key string
expect putResult
}{
{
key:"canceled",
expect: putResult{
putResponse:nil,
err: context.Canceled,
},
},
{
key:"deadline_exceeded",
expect: putResult{
putResponse:nil,
err: context.DeadlineExceeded,
},
},
{
key:"err_empty_key",
expect: putResult{
putResponse:nil,
err: rpctypes.ErrEmptyKey,
},
},
{
key:"default",
expect: putResult{
putResponse:nil,
err: defaultErr,
},
},
{
key:"fine",
expect: putResult{
putResponse:nil,
err: nil,
},
},
}
for index, test := range tests {
_, err := api.Put(context.Background(), test.key,"oktestut")
assert.EqualValuesf(t, test.expect.err, err,"case: %d", index)
}
}
Makefile
export GOPATH = $(shell pwd)/../../..
TEST_FLAGS=-test.short -v
PKGS = gounit/etcd
print:
echo$(GOPATH)
dep:
go get "go.etcd.io/etcd/clientv3"
go get "github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
go get "github.com/stretchr/testify/assert"
vet:dep
go fmt ./...
go vet ./...
test:vet
go test --cover$(PKGS)
cover-tool:
go get github.com/jstemmer/go-junit-report
go get golang.org/x/tools/cmd/cover
go get github.com/axw/gocov/gocov
go get github.com/AlekSi/gocov-xml
go get github.com/wadey/gocovmerge
unit-coverage: dep cover-tool
mkdir -p report
cat /dev/null > report/utest.out
$(foreach i,$(PKGS),go test $(i) $(TEST_FLAGS) --covermode=count -coverprofile=report/cover-`echo $(i) |sed 's/\//./g'`.out >> report/utest.out;)
cat report/utest.out | go-junit-report > report/unit_test_report.xml
gocovmerge report/cover-*.out > report/unit_test_coverage.out
gocov convert report/unit_test_coverage.out | gocov-xml > report/unit_test_coverage.xml
go tool cover -html=report/unit_test_coverage.out -o report/unit_test_coverage.html
rm report/{cover-*,utest}.out
clean:
rm -rf report
有疑问加站长微信联系(非本文作者)