介绍

1.所有文件名为xxx_test.go被识别为单元测试文件
2.函数名为Test开头表示逻辑测试
3.函数名为Benchmark开头表示性能测试
4.函数姓名为Example开头表示示例函数,用于生成函数文档

命令汇总

  1. 1.执行所有单测(必须在单测所在目录执行)
  2. go test
  3. 2.执行指定单测
  4. go test -run=Testxxx
  5. 3.执行指定测试组中某个case
  6. go test-run=Textxxx/case_1
  7. 4.查看详细信息
  8. go test -v
  9. 5.查看单侧覆盖率(单测和要测试的方法必须在同一个包下否则无法统计)
  10. go test -cover
  11. 6.覆盖率输出文件
  12. go test -cover -coverprofile=cover.out
  13. 7.通过html分析覆盖率文件
  14. go tool cover -html=cover.out
  15. 8.跳过测试(需要结合Testing.Short()开关使用,请参考示例)
  16. go test -short
  17. 9.性能基准测试(go test 不会执行性能基准测试)
  18. go test -bench=Split
  19. 10.性能基线测试查看内存分配情况
  20. go test -bench=Split -benchmem
  21. 11.性能基线测试执行测试时间
  22. go test -bench=Split -benchtime=20s
  23. 11.性能基线测试执行CPU数量执行
  24. go test -bench=Split -cpu=1

逻辑测试

所有测试函数必须以Test开头

1.准备一个需要测试的方法

  1. package splitstr
  2. import (
  3. "strings"
  4. )
  5. func SplitString(str, sep string) []string {
  6. var ss = make([]string, 0)
  7. i := strings.Index(str, sep)
  8. for i > -1 {
  9. ss = append(ss, str[:i])
  10. str = str[i+len(sep):]
  11. i = strings.Index(str, sep)
  12. }
  13. ss = append(ss, str)
  14. return ss
  15. }

2.对函数进行测试

  1. package tests
  2. import (
  3. "go_chat/splitstr"
  4. "reflect"
  5. "testing"
  6. )
  7. //单元测试
  8. //1.所有文件名为xxx_test.go被识别为单元测试文件
  9. //2.函数名为Test开头表示测试函数逻辑
  10. //3.
  11. ////命令行输入 go test -run=Test1Split -v
  12. //表示只验证这一个函数
  13. //-v 表示输出详细信息
  14. //必须在当前xxx_test.go所在目录下执行命令才可执行单侧
  15. func Test1Split(t *testing.T) {
  16. ret := splitstr.SplitString("1_2_3_4", "_")
  17. want := []string{"1", "2", "3", "4"}
  18. if !reflect.DeepEqual(ret, want) {
  19. t.Errorf("want:%v but got:%v\n", want, ret)
  20. }
  21. }
  22. func Test2Split(t *testing.T) {
  23. //当开始short时进行方法跳过,按需使用
  24. if testing.Short(){
  25. t.Skip("跳过该测试方法")
  26. }
  27. ret := splitstr.SplitString("1_2_3_4", "_")
  28. want := []string{"1", "2", "3", "5"}
  29. if !reflect.DeepEqual(ret, want) {
  30. t.Fatalf("want:%v but got:%v\n", want, ret)
  31. }
  32. }

3.通过测试组进行批量测试

  1. package tests
  2. import (
  3. "go_chat/splitstr"
  4. "reflect"
  5. "testing"
  6. )
  7. func TestSplit(t *testing.T) {
  8. type test struct {
  9. input string
  10. sep string
  11. want []string
  12. }
  13. tests := map[string]test{
  14. "case_1": {input: "1_2_3_4", sep: "_", want: []string{"1", "2", "3", "4"}},
  15. "case_2": {input: "1_2_43_4", sep: "_", want: []string{"1", "2", "3", "4"}},
  16. }
  17. //命令行输入 go test -run=TestSplit/case_1
  18. //表示只包这一个单测
  19. for name,tc :=range tests{
  20. t.Run(name, func(t *testing.T) {
  21. ret:=splitstr.SplitString(tc.input,tc.sep)
  22. if !reflect.DeepEqual(ret,tc.want){
  23. t.Fatalf("want:%v but got:%v\n", tc.want, ret)
  24. }
  25. })
  26. }
  27. }

4.并行测试

结合t.Parallel()实现

  1. package tests
  2. import (
  3. "go_chat/splitstr"
  4. "reflect"
  5. "testing"
  6. )
  7. func TestSplit(t *testing.T) {
  8. t.Parallel()//开启并行测试
  9. type test struct {
  10. input string
  11. sep string
  12. want []string
  13. }
  14. tests := map[string]test{
  15. "case_1": {input: "1_2_3_4", sep: "_", want: []string{"1", "2", "3", "4"}},
  16. "case_2": {input: "1_2_43_4", sep: "_", want: []string{"1", "2", "43", "4"}},
  17. }
  18. //命令行输入 go test -run=TestSplit/case_1
  19. //表示只包这一个单测
  20. for name,tc :=range tests{
  21. tc:=tc //注意这里重新声明tc变量(避免多个goroutine中使用了相同的变量)
  22. t.Run(name, func(t *testing.T) {
  23. ret:=splitstr.SplitString(tc.input,tc.sep)
  24. if !reflect.DeepEqual(ret,tc.want){
  25. t.Fatalf("want:%v but got:%v\n", tc.want, ret)
  26. }
  27. })
  28. }
  29. }

5.代码生成工具

安装
go get -u github.com/cweill/gotests
#命令行执行
go tests -all -w split_str.go
#goland
image.png

生成测试如下

  1. package splitstr
  2. import (
  3. "reflect"
  4. "testing"
  5. )
  6. func TestSplitString(t *testing.T) {
  7. type args struct {
  8. str string
  9. sep string
  10. }
  11. tests := []struct {
  12. name string
  13. args args
  14. want []string
  15. }{
  16. {name: "s", args: args{str: "", sep: ""}, want: []string{}},
  17. }
  18. for _, tt := range tests {
  19. t.Run(tt.name, func(t *testing.T) {
  20. if got := SplitString(tt.args.str, tt.args.sep); !reflect.DeepEqual(got, tt.want) {
  21. t.Errorf("SplitString() = %v, want %v", got, tt.want)
  22. }
  23. })
  24. }
  25. }

性能基准测试

  1. package splitstr
  2. import (
  3. "reflect"
  4. "testing"
  5. )
  6. //命令行执行 go test -bench=Split
  7. func BenchmarkSplit(b *testing.B) {
  8. //b.N 表示执行的次数
  9. for i := 0; i < b.N; i++ {
  10. SplitString("1_2","_")
  11. }
  12. }

基准测试并不会默认执行,需要增加-bench参数,所以我们通过执行go test -bench=Split命令执行基准测试,输出结果如下:
go test -bench=Split
image.png
其中BenchmarkSplit-8表示对Split函数进行基准测试,数字8表示GOMAXPROCS的值,这个对于并发基准测试很重要。16190835和81.3ns/op表示每次调用Split函数耗时203ns,这个结果是16190835次调用的平均值。
我们还可以为基准测试添加-benchmem参数,来获得内存分配的统计数据。
go test -bench=Split -benchmem
image.png
其中,48 B/op表示每次操作内存分配了48字节,2 allocs/op则表示每次操作进行了2次内存分配。

性能比较测试

性能比较函数通常是一个带有参数的函数,被多个不同的Benchmark函数传入不同的值来调用。例如两个相同功能的方法,通过性能计较计算出那个方法的性能更优

并发测试