介绍
1.所有文件名为xxx_test.go被识别为单元测试文件
2.函数名为Test开头表示逻辑测试
3.函数名为Benchmark开头表示性能测试
4.函数姓名为Example开头表示示例函数,用于生成函数文档
命令汇总
1.执行所有单测(必须在单测所在目录执行)
go test
2.执行指定单测
go test -run=Testxxx
3.执行指定测试组中某个case
go test-run=Textxxx/case_1
4.查看详细信息
go test -v
5.查看单侧覆盖率(单测和要测试的方法必须在同一个包下否则无法统计)
go test -cover
6.覆盖率输出文件
go test -cover -coverprofile=cover.out
7.通过html分析覆盖率文件
go tool cover -html=cover.out
8.跳过测试(需要结合Testing.Short()开关使用,请参考示例)
go test -short
9.性能基准测试(go test 不会执行性能基准测试)
go test -bench=Split
10.性能基线测试查看内存分配情况
go test -bench=Split -benchmem
11.性能基线测试执行测试时间
go test -bench=Split -benchtime=20s
11.性能基线测试执行CPU数量执行
go test -bench=Split -cpu=1
逻辑测试
1.准备一个需要测试的方法
package splitstr
import (
"strings"
)
func SplitString(str, sep string) []string {
var ss = make([]string, 0)
i := strings.Index(str, sep)
for i > -1 {
ss = append(ss, str[:i])
str = str[i+len(sep):]
i = strings.Index(str, sep)
}
ss = append(ss, str)
return ss
}
2.对函数进行测试
package tests
import (
"go_chat/splitstr"
"reflect"
"testing"
)
//单元测试
//1.所有文件名为xxx_test.go被识别为单元测试文件
//2.函数名为Test开头表示测试函数逻辑
//3.
////命令行输入 go test -run=Test1Split -v
//表示只验证这一个函数
//-v 表示输出详细信息
//必须在当前xxx_test.go所在目录下执行命令才可执行单侧
func Test1Split(t *testing.T) {
ret := splitstr.SplitString("1_2_3_4", "_")
want := []string{"1", "2", "3", "4"}
if !reflect.DeepEqual(ret, want) {
t.Errorf("want:%v but got:%v\n", want, ret)
}
}
func Test2Split(t *testing.T) {
//当开始short时进行方法跳过,按需使用
if testing.Short(){
t.Skip("跳过该测试方法")
}
ret := splitstr.SplitString("1_2_3_4", "_")
want := []string{"1", "2", "3", "5"}
if !reflect.DeepEqual(ret, want) {
t.Fatalf("want:%v but got:%v\n", want, ret)
}
}
3.通过测试组进行批量测试
package tests
import (
"go_chat/splitstr"
"reflect"
"testing"
)
func TestSplit(t *testing.T) {
type test struct {
input string
sep string
want []string
}
tests := map[string]test{
"case_1": {input: "1_2_3_4", sep: "_", want: []string{"1", "2", "3", "4"}},
"case_2": {input: "1_2_43_4", sep: "_", want: []string{"1", "2", "3", "4"}},
}
//命令行输入 go test -run=TestSplit/case_1
//表示只包这一个单测
for name,tc :=range tests{
t.Run(name, func(t *testing.T) {
ret:=splitstr.SplitString(tc.input,tc.sep)
if !reflect.DeepEqual(ret,tc.want){
t.Fatalf("want:%v but got:%v\n", tc.want, ret)
}
})
}
}
4.并行测试
结合t.Parallel()实现
package tests
import (
"go_chat/splitstr"
"reflect"
"testing"
)
func TestSplit(t *testing.T) {
t.Parallel()//开启并行测试
type test struct {
input string
sep string
want []string
}
tests := map[string]test{
"case_1": {input: "1_2_3_4", sep: "_", want: []string{"1", "2", "3", "4"}},
"case_2": {input: "1_2_43_4", sep: "_", want: []string{"1", "2", "43", "4"}},
}
//命令行输入 go test -run=TestSplit/case_1
//表示只包这一个单测
for name,tc :=range tests{
tc:=tc //注意这里重新声明tc变量(避免多个goroutine中使用了相同的变量)
t.Run(name, func(t *testing.T) {
ret:=splitstr.SplitString(tc.input,tc.sep)
if !reflect.DeepEqual(ret,tc.want){
t.Fatalf("want:%v but got:%v\n", tc.want, ret)
}
})
}
}
5.代码生成工具
安装
go get -u github.com/cweill/gotests
#命令行执行
go tests -all -w split_str.go
#goland

生成测试如下
package splitstr
import (
"reflect"
"testing"
)
func TestSplitString(t *testing.T) {
type args struct {
str string
sep string
}
tests := []struct {
name string
args args
want []string
}{
{name: "s", args: args{str: "", sep: ""}, want: []string{}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := SplitString(tt.args.str, tt.args.sep); !reflect.DeepEqual(got, tt.want) {
t.Errorf("SplitString() = %v, want %v", got, tt.want)
}
})
}
}
性能基准测试
package splitstr
import (
"reflect"
"testing"
)
//命令行执行 go test -bench=Split
func BenchmarkSplit(b *testing.B) {
//b.N 表示执行的次数
for i := 0; i < b.N; i++ {
SplitString("1_2","_")
}
}
基准测试并不会默认执行,需要增加-bench参数,所以我们通过执行go test -bench=Split命令执行基准测试,输出结果如下:
go test -bench=Split
其中BenchmarkSplit-8表示对Split函数进行基准测试,数字8表示GOMAXPROCS的值,这个对于并发基准测试很重要。16190835和81.3ns/op表示每次调用Split函数耗时203ns,这个结果是16190835次调用的平均值。
我们还可以为基准测试添加-benchmem参数,来获得内存分配的统计数据。
go test -bench=Split -benchmem
其中,48 B/op表示每次操作内存分配了48字节,2 allocs/op则表示每次操作进行了2次内存分配。
性能比较测试
性能比较函数通常是一个带有参数的函数,被多个不同的Benchmark函数传入不同的值来调用。例如两个相同功能的方法,通过性能计较计算出那个方法的性能更优