go 语言发展非常迅速,大家对go语言编程也比较熟悉了,但很多同学对于go语言的测试不太熟悉,最近准备三篇关于Go语言的测试文章来介绍Go语言的测试相关内容。
单元测试框架
go语言提供了编写go语言的自动化测试框架testing.T,testing.B等,我们通过go test
命令就可以来启动测试。我们编写测试方法的格式如下:
func TestXxx(*testing.T)
注意这里的方法名TestXxx
中第一个X是大写,这是一种推荐的规范。测试方法名在实际方法名Xxx
前加Test
标明这是测试Xxx
的方法。
另外,我们推荐将测试文件取名xxx_test.go
这样的格式,其中xxx
为go源文件的名称,方便我们定位某个文件的测试文件。go测试文件和源文件放在同一个目录下。该文件将从常规软件包构建中排除,但在运行go test
命令时将包含该文件。
单元测试编写规范
单元测试通常都是通过一组用例数据,作为方法的参数传入,检查输出是否与预期的返回值相同。这种思路也适用于Go语言,只不过在实现形式上推荐采用更为优雅的方式。
假设我们有一个非常简单的helper.go
, 实现两个整数相加输出结果的功能,实现代码如下:
package helper
func Add(a, b int) int {
return a + b
}
我们可以写如下的测试代码:
package helper
import (
"testing"
)
func TestAdd(t *testing.T) {
var param1 = 1
var param2 = 1
var result = 2
r := Add(param1, param2)
if r != result {
if r != result {
t.Errorf("error: expecte %d, but got %d", result, r)
}
}
}
这个代码这样写并没有什么大的问题,如果考虑其扩展性,比如增加新的测试场景(代码在不断迭代优化中),代码的可读性就会变得越来越差,如何有效确保扩展性的前提下不降低可读性呢?推荐如下方式:
package helper
import (
"testing"
)
func TestAdd(t *testing.T) {
tests := []struct {
param1 int
param2 int
result int
}{
{
param1: 1,
param2: 1,
result: 2,
},
}
for _, test := range tests {
r := Add(test.param1, test.param2)
if r != test.result {
t.Errorf("error: expecte %d, but got %d", test.result, r)
}
}
}
这种方式下,测试代码更加简洁,在增加新的测试场景的情况下,也不会降低可读性,这种设计在Kubernetes及阿里Pouch等开源项目中都有此类实践,大家可以关注。
特殊功能开关
指定运行的方式
可以通过go test -run xxx
的形式来指定运行的方法,注意这里的run
参数是正则匹配的,如下所示:
bogon:helper $ go test -v
=== RUN TestAdd
--- PASS: TestAdd (0.00s)
=== RUN TestExp
--- PASS: TestExp (0.00s)
PASS
ok demo/helper 0.005s
bogon:helper $ go test -run TestAdd -v
=== RUN TestAdd
--- PASS: TestAdd (0.00s)
PASS
ok demo/helper 0.005s
bogon:helper $ go test -run TestExp -v
=== RUN TestExp
--- PASS: TestExp (0.00s)
PASS
ok demo/helper 0.005s
获取测试覆盖率
go 提供了获取单元测试覆盖率参数,执行如下命令:
go test -v -coverprofile cover.out
go tool cover -html=cover.out -o cover.html
我们打开cover.html就可以获得单元测试覆盖率信息,如下所示:
限制同时执行的线程数
go语言有一个GOMAXPROCS变量,可以指定运行Go代码的操作系统线程数。如果执行时不加该参数,则就是当前所设置的GOMAXPROCS值。
bogon:helper $ go test -cpu 1
PASS
ok demo/helper 0.005s
总结
Go语言是一个严禁且高效的开发语言,在单元测试方面,提供了很多好的工程实践,这些思想可以在其他语言中采用,这一篇是一个开始,后续会介绍Go语言测试的Benchmark部分,主要是针对性能相关部分的内容。