简单介绍:单元测试、Go test
这里记录的是我个人不太熟练的语法和知识
详细内容移步:李文周的博客(非常详细)
https://www.liwenzhou.com/posts/Go/16_test/#autoID-0-0-0
(因为当时没什么函数测试,所以就抄了,嘿嘿嘿)
#测试函数
在一个splist.go文件内写入需要被测试的函数,文件名可以随意,但是为了‘值观对应’一般会与文件名相同;
在一个.go文件中,如果存在多个需要被测试的函数,则需要…一般是什么文件就_test什么文件…
在Goland IDE中可以通过按住Ctrl键并指向被测试函数并按下会出现相关内容
//切分字符串// 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 一下
当然,只测试一个示例就太草率了
通过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 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方式打开,直接将文件拖到浏览器是不行的,必须用上述命令。
#性能基准测试
原理:调用非常非常多次看看函数的:平均执行时间、内存申请消耗、等等(???)。
func BenchmarkSplit(b *testing.B) { // b.N 不是固定的数 但至少保证跑够1秒 for i := 0; i < b.N; i++ { Split("前中后", "中") }}
go test -bench=Split
数据解释
BenchmarkSplit-8 (-8 go maxprocess真正干活的进程数) (cpu干活数)
12269937 执行次数
97.5 ns/op 每一次 *** 作耗费了97.5纳秒
但是,一般我们测试的时候会加上**-benchmem**,统计内存分配情况。
数据解释
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/
以上是内存溢出为你收集整理的Go单元测试 13全部内容,希望文章能够帮你解决Go单元测试 13所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)