Golang 中如何做好单元测试

Posted by Robin on August 31, 2019

单元测试是保证软件质量的最基本的测试,也是各种测试中执行成本较低、粒度较小的一种。由开发者在开发软件功能的同时,添加单元测试代码来保证各函数的逻辑的正确性。 如果很多缺陷能够通过单元测试发现,被开发者在开发功能过程中解决,就能避免这些缺陷进入软件生命周期的后续阶段,极大地减少解决这些缺陷的成本。 因此,保证代码的单元测试覆盖率,是一个程序员职业素养的重要体现,也会软件质量的重要保证。本文主要介绍 Golang 中如何做好单元测试。

Unit Test Coverage

Golang 不仅自带跑单元测试的命令,同时也提供单元测试覆盖率的统计和分析工具。下面以开源 Golang 项目 Cyclone 为例,详细介绍如何清晰地了解你代码的单元测试覆盖率。

提前下载 Cyclone 项目的源码到本地,并进入该项目的目录下

$ go get github.com/caicloud/cyclone
$ cd $GOPATH/src/github.com/caicloud/cyclone

Unit Test

为了分析单元测试覆盖率,首先需要运行单元测试。在平时运行单元测试 go test 命令后面需要加入 -coverprofile 将各个 package 的单元测试覆盖率的概况信息输出到文件中。

# 获得需要分析单元测试覆盖率的 package,可以过滤掉 vendor 等特殊目录
$ PKGS=$(go list ./... | grep -v /vendor | grep -v /test)
# 运行单元测试,同时将测试覆盖率结果输出到文件
$ go test $PKGS -coverprofile=coverage.out
...
?       github.com/caicloud/cyclone/pkg/workflow/coordinator/cycloneserver      [no test files]
?       github.com/caicloud/cyclone/pkg/workflow/coordinator/k8sapi     [no test files]
ok      github.com/caicloud/cyclone/pkg/workflow/values/ref     0.034s  coverage: 88.0% of statements
ok      github.com/caicloud/cyclone/pkg/workflow/workflowrun    3.054s  coverage: 33.6% of statements
?       github.com/caicloud/cyclone/pkg/workflow/workload/delegation    [no test files]
ok      github.com/caicloud/cyclone/pkg/workflow/workload/pod   0.032s  coverage: 61.4% of statements
?       github.com/caicloud/cyclone/tools/generator/client-gen  [no test files]
ok      github.com/caicloud/cyclone/tools/generator/client-gen/args     0.012s  coverage: 40.3% of statements
?       github.com/caicloud/cyclone/tools/generator/client-gen/generators       [no test files]
?       github.com/caicloud/cyclone/tools/generator/client-gen/generators/fake  [no test files]
?       github.com/caicloud/cyclone/tools/generator/client-gen/generators/scheme        [no test files]
ok      github.com/caicloud/cyclone/tools/generator/client-gen/generators/util  0.010s  coverage: 78.0% of statements
?       github.com/caicloud/cyclone/tools/generator/client-gen/path     [no test files]
ok      github.com/caicloud/cyclone/tools/generator/client-gen/types    0.009s  coverage: 26.1% of statements
...

Unit Test Analysis

上面产生的 coverage.out 是各 package 的单元测试覆盖率信息,接下来需要用 go tool covercoverage.out 进行分析,获得整个项目的单元测试覆盖率。

$ go tool cover -func coverage.out | tail -n 1 | awk '{ print "Total coverage: " $3 }'
Total coverage: 42.6%

如果整体的单元测试覆盖率较低,需要知道每段具体代码的单元测试覆盖情况,便于有针对增加单元测试,可以通过下面命令展示更详细信息。

$ go tool cover -html coverage.out

上述命令会自动打开浏览器,明确指出每个文件中的每段代码的单元测试覆盖情况,如下图所示:

golang-ut-coverage

Reference