Go单元测试 13

简单介绍:单元测试、Go test
这里记录的是我个人不太熟练的语法和知识
详细内容移步:李文周的博客(非常详细)
https://www.liwenzhou.com/posts/Go/16_test/#autoid-0-0-0
(因为当时没什么函数测试,所以就抄了,嘿嘿嘿)
#测试函数
在一个splist.go文件内写入需要被测试的函数,文件名可以随意,但是为了‘值观对应’一般会与文件名相同;
在一个.go文件中,如果存在多个需要被测试的函数,则需要…一般是什么文件就_test什么文件…
在Goland IDE中可以通过按住Ctrl键并指向被测试函数并按下会出现相关内容
Go单元测试 13

//切分字符串
// Split 将s按照spe进行切割,返回一个字符串的切片
// Split("我爱你","爱") => ["我","你"]
func Split(s, sep string) (ret []string) {
	ret = make([]string, 0, strings.Count(s, sep)+1)
	idx := strings.Index(s, sep)
	for idx > -1 {
		ret = append(ret, s[:idx]) // append()函数在容量不够的情况下会申请内存
		s = s[idx+len(sep):]
		idx = strings.Index(s, sep)
	}
	ret = append(ret, s)
	return
}

这样被测试函数就定义好了

#测试用例
在文件夹中创建split_test.go的测试文件,也可以在别的文件夹中创建,但是要导包。
测试函数的首字母必须是大写Test+被测试函数名
**还需要接收一个*testing.T类型参数

func TestSplit(t *testing.T) {
	//got := Split("我爱你", "爱")
	//want := []string{"我", "你"}
	//切片不能直接比较,channel、map同样
	got := Split("a:b:c", ":")
	want := []string{"a", "b", "c"}
	if !reflect.DeepEqual(got, want) { //DeepEqual用与比较"不能比较的"和"引用类型的比较"
		t.Errorf("want:%v got:%v", want, got)
	}
}

go test 一下

Go单元测试 13

当然,只测试一个示例就太草率了
通过map类型,尽可能覆盖输入输出的多种情况。

func TestSplit(t *testing.T) {
	type test struct {
		input string
		sep   string
		want  []string
	}
	tests := map[string]test{
		"simple":  {input: "a:b:c", sep: ":", want: []string{"a", "b", "c"}},
		"chinese": {input: "傻-逼", sep: "-", want: []string{"傻", "逼"}},
	}

	for name, tc := range tests {
		got := Split(tc.input, tc.sep)
		if !reflect.DeepEqual(got, tc.want) {
			t.Errorf("name %v failed, want:%v got:%v ", name, tc.want, got)
		}
	}
}

当然测试时候可能需要查看具体某一个测试用例的具体情况
go test -v 需要这个t.Run()函数才能能看到具体是某个Test函数的具体情况

func TestSplit(t *testing.T) {
	type test struct {
		input string
		sep   string
		want  []string
	}
	tests := map[string]test{
		"simple":  {input: "a:b:c", sep: ":", want: []string{"a", "b", "c"}},
		"chinese": {input: "傻-逼", sep: "-", want: []string{"傻", "逼"}},
	}
	for name, tc := range tests {
		t.Run(name, func(t *testing.T) {
			got := Split(tc.input, tc.sep)
			if !reflect.DeepEqual(got, tc.want) {
				t.Errorf("name %v failed, want:%v got:%v ", name, tc.want, got)
			}
		})
	}
}

Go单元测试 13

此外还可以单独测试指定用例
go test -run=Split/chinese 单独跑一个测试用例(不演示了)
这里的chinese是指map类型里面的"chinese"
效果与单独测试一个函数相同

#重置时间

func BenchmarkSplit(b *testing.B) {
	time.Sleep(5 * time.Second) // 假设需要做一些耗时的无关操作
	b.ResetTimer()              // 重置计时器
	for i := 0; i < b.N; i++ {
		Split("沙河有沙又有河", "沙")
	}
}

#查看覆盖率
在我自己看来,这是最(迪奥)的东西。
go test -cover
还可以具体查看覆盖了那些代码
go test -coverprofile=c.out
覆盖率可视化输出到c.out(随意文件名.随意文件后缀名)
go tool cover -html=c.out
将c.out文件以html方式打开,直接将文件拖到浏览器是不行的,必须用上述命令。
Go单元测试 13

#性能基准测试
原理:调用非常非常多次看看函数的:平均执行时间、内存申请消耗、等等(???)。

func BenchmarkSplit(b *testing.B) {
	// b.N 不是固定的数 但至少保证跑够1秒
	for i := 0; i < b.N; i++ {
		Split("前中后", "中")
	}
}

go test -bench=Split
Go单元测试 13
数据解释
BenchmarkSplit-8 (-8 go maxprocess真正干活的进程数) (CPU干活数)
12269937 执行次数
97.5 ns/op 每一次操作耗费了97.5纳秒

但是,一般我们测试的时候会加上**-benchmem**,统计内存分配情况。
Go单元测试 13
数据解释
32B/op 每次操作消耗的内存
1 allocs/op 每次操作的内存申请数

#性能比较函数

测试函数的性能一般是使用对比方法,但上面的测试方式多少有点单薄,所以大多数情况是使用比较的方式。
在同一个问题下,有多种的处理方法。
比如我们想知道一个函数处理1W次和10W次的耗时是多少,或则对两个不同算法实现相同的效果时,新能差别是多少。

(这是抄的)
被测试函数

func Asd(n int) int {
	i := 0
	for {
		if n == 1 {
			return i
		}
		n = n / 2
		i++
	}
}

测试函数

func benchmarkFib(b *testing.B, n int) {
	for i := 0; i < b.N; i++ {
		Fib(n)
	}
}

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 BenchmarkFib20(b *testing.B) { benchmarkFib(b, 20) }
func BenchmarkFib40(b *testing.B) { benchmarkFib(b, 40) }

**go test -bench=.**test全部
go test -bench=Fib40 -benchtime=20stest Fib40 跑够20秒

#并行测试

func BenchmarkSplitParallel(b *testing.B) {
	// b.SetParallelism(1) // 设置使用的CPU数
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			Split("沙河有沙又有河", "沙")
		}
	})
}

https://www.liwenzhou.com/posts/Go/16_test/#autoid-0-0-0
https://www.bilibili.com/video/av66788366/

上一篇:03.vscode技巧2


下一篇:华为云账号注册流程