Golang单元测试与断言编写流程详解

go test

编写单元测试

go中单元测试与语言中其他特性一样具有独特见解,如格式化、命名规范。语法有意避免使用断言,并将检查值和行为的责任留给开发人员。

下面通过示例进行说明。我们编写Sum函数,实现数据求和功能:

然后在单独的文件中编写测试代码,测试文件可以在相同包中,或不同包中。测试代码如下:

Golang测试功能特性:

t *testing.Tt.Errort.Failt.Errorft.Logsomething_test.goaddition_test.go

批量测试(test tables)

test tables
return x*y

=== RUN   TestSum
    math_test.go:61: Sum of (1+1) was incorrect, got: 1, want: 2.
    math_test.go:61: Sum of (1+2) was incorrect, got: 2, want: 3.
    math_test.go:61: Sum of (5+2) was incorrect, got: 10, want: 7.
--- FAIL: TestSum (0.00s)

FAIL

单元测试不仅要正向测试,更要进行负向测试。

执行测试

执行测试有两种方法:

在相同目录下运行命令:

go test 

这会匹配任何packagename_test.go的任何文件。

使用完整的包名

go test

go test -v

单元测试和集成测试的区别在于单元测试通常不依赖网络、磁盘等,仅测试一个功能,如函数。

-cover

如果执行下面命令,可以生成html文件,以可视化方式查看覆盖率:

go test -cover -coverprofile=c.out
go tool cover -html=c.out -o coverage.html 

性能测试

benchmark 测试衡量程序性能,可以比较不同实现差异,理解影响性能原因。

go性能测试也有一定规范:

BenchmarkBenchmarkFunctionName()Benchmark_functionName()Benchmarkfunctionname()

虽然可以把单元测试和性能测试代码放在相同文件,但尽量避免,文件命名仍然以_test.go结尾。如单元测试文件为simple_test.go,性能测试为benchmark_test.go。

下面通过示例进行说明,首先定义函数:

先编写单元测试,分别编写正向测试和负向测试:

接着编写基准测试(性能测试):

执行性能测试

go test -bench . -run notest

.

我们还可以指定其他参数,下面示例指定count为2,表示对现有测试执行两次分析。设置GOMAXPROCS为4,查看测试的内存情况,执行这些请求时间为2秒,而不是默认的1秒执行时间。命令如下:

$ go test -bench=. -benchtime 2s -count 2 -benchmem -cpu 4 -run notest
goos: windows
goarch: amd64
pkg: gin01/math
cpu: Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz
BenchmarkIsPalindrome
BenchmarkIsPalindrome-4         1000000000               1.349 ns/op           0 B/op          0 allocs/op
BenchmarkIsPalindrome-4         1000000000               1.356 ns/op           0 B/op          0 allocs/op
PASS
ok      gin01/math      3.234s

-410000000001.349 ns/opPASS

配置计算时间

定义函数:

对应单元测试如下:

每次执行前,随机生成数组,造成性能测试不准确。

为了更准确计算时间,可以使用下面函数进行控制:

-StopTimer() : 停止计时器方法.

-StartTimer() : 启动计时器方法.

-ResetTimer() : 重置计时器方法.

最终性能测试函数如下:

断言(assertion)

github.com/stretchr/testify/assert

assert示例

assert子库提供了便捷的断言函数,可以大大简化测试代码的编写。总的来说,它将之前需要判断 + 信息输出的模式:

观察到上面的断言都是以TestingT为第一个参数,需要大量使用时比较麻烦。testify提供了一种方便的方式。先以testing.T创建一个Assertions对象,Assertions定义了前面所有的断言方法,只是不需要再传入TestingT参数了。

TestingT类型定义如下,就是对*testing.T做了一个简单的包装:

下面引用官网的一个示例。

首先定义功能函数Addition:

测试代码: