自己给自己的代码写测试
- 都是以
_test
为后缀名的源代码文件,都是go test测试的一部分,不会被go build编译到最终的可执行文件中 *_test.go
文件中有三种类型的函数,单元测试函数、基准测试函数和示例函数- 测试函数:前缀为Test,测试程序的一些逻辑行为是否可行
- 基准函数:函数名前缀为Benchmark ,测试函数的性能
- 示例函数:前缀为Example,提供示例文档
go test
命令会遍历所有的*_test.go
文件中符合上述命名规则的函数,生成一个临时的main包用于调用相应的测试函数,然后构建并运行、报告测试结果,最后清理临时文件测试函数
每个测试函数必须导入testing包
其中t用于报告测试失败和附加的日志信息func TestName(t *testing.T){
// ...
got := ...
want := ...
// 引用类不能直接比较,使用reflect.DeepEqual(want,got)
// 错误 t.Errorf()
}
go test -v 查看详细信息
测试组和子测试
测试组:在一个函数中写多个测试样例
type test []struct{
input string
sep string
want []string
}
test := test{
{input: "a:b:c", sep:":", want []string{a,b,c}},
{},
{},
{},
}
for _,tc := range tests {
got := Split(tc.input, tc.sep)
if !reflect.DeepEqual(got,tc.want){
// error
}
}
但是当测试用例比较多,没法一眼看出具体哪个测试用例失败,可以使用子测试
type test []struct{
input string
sep string
want []string
}
test := map[string]test{
"s1":{input: "a:b:c", sep:":", want []string{a,b,c}},
"s2":{},
"s3":{},
"s4":{},
}
for _,tc := range tests {
got := Split(tc.input, tc.sep)
if !reflect.DeepEqual(got,tc.want){
// error
}
}
然后如果某个子测试错了,可以使用go test -v -run=Split/simple
指挥运行simple对应的子测试用例
测试覆盖率
测试至少被运行一次的代码占总代码的比例 使用go test -cover
,可以看到代码被测试覆盖的百分比
go还提供了一个-coverprofile
,可以将覆盖率的记录信息输出到文件中。go test cover -coverprofile=c.out
或 go test cover -html=c.out
性能基准测试
基准测试就是在一定的工作负载之下检测程序性能的一种方法,它必须要执行b.N
次,这样测试才有对照性
func BenchmarkName(b *testing.B){
for i:=0;i<b.N;i++{
}
}
执行 go test -bench=Split
会显示核数,执行次数以及 op每次操作执行时间
还可以添加-benchmem
参数,可以显示每次操作的内核申请情况
性能比较函数
func benchmarkFib(b *testing.B,n int){
}
func BenchmarkFib1(b *testing.B) {benchmarkFib(b,1)}
func BenchmarkFib2(b *testing.B) {benchmarkFib(b,2)}
func BenchmarkFib3(b *testing.B) {benchmarkFib(b,3)}
func BenchmarkFib10(b *testing.B) {benchmarkFib(b,10)}
func BenchmarkFib100(b *testing.B) {benchmarkFib(b,100)}
运行 go test -bench=.
可以使用-benchtime
标志增加最小基准时间,以产生更准确的结果
重置时间
可以使用b.ResetTimer()
,之前的操作不做为测试报告操作
并行测试
func (b *B) RunParallel(body func(*PB))
会以并行的方式执行给定的基准测试
性能优化
- CPU
- MEM(Heap)
- Block
- Goroutine
go pprof