golang testing使用示例小结
作者:动态一时爽,重构火葬场
testing包服务于自动化测试
基本测试
Table Drvien Test
基于表的测试通过表形式进行测试每种情况的输入和期望输出,从而测试程序的正确性
func TestFib(t *testing.T) { var fibTests = []struct { in int // input expected int // expected result }{ {1, 1}, {2, 1}, {3, 2}, {4, 3}, {5, 5}, {6, 8}, {7, 13}, } for _, tt := range fibTests { actual := Fib(tt.in) if actual != tt.expected { t.Errorf("Fib(%d) = %d; expected %d", tt.in, actual, tt.expected) } } }
- 跳过测试
- SkipNow(): 跳过测试
- Skip(): 跳过测试并输出log
- Skipf(): 跳过测试并格式化输出log
- 失败但继续
- Fail(): 标记测试失败,但继续执行
- FailNow(): 标记测试失败,不继续执行
- Error(): 标记测试失败,并输出
- Errorf(): 标记测试失败,并格式化输出
- 输出
- Log(): 输出
- Logf(): 格式化输出
- 失败且中断
- Fatal(): 相当于FailNow() + Log()
- Fatalf(): 相当于FailNow() + Logf()
Parallel()
Parallel方法表示会和其他带有Parallel方法的测试并行执行
ExampleXXX()
ExampleXXX方法中如果含有Output:
开头的行注释,则会在运行测试期间,将输出和注释中的值相比较
如果是不确定的顺序,则可以以
Unordered output:
作为开头
但如果没有这样的注释,这就是一个普通函数,不能被直接运行
压力测试
压力测试方法以func BenchmarkXXX(*testing.B)
函数名展现。
函数体格式如下
func BenchmarkHello(b *testing.B) { for i := 0; i < b.N; i++ { // do sth } }
压力测试会自动调整b.N使得持续足够长时间
重置计时器
如果想要跳过不需要计时的耗时工作,那么可以通过b.ResetTimer()
重置计时器
并行测试
如果想并行压力测试,那么可以通过RunParallel
实现
func BenchmarkHelloParallel(b *testing.B) { b.RunParallel(func(pb *testing.PB) { // do sth }) }
内存统计
ReportAllocs
方法用于打开内存统计功能
输出结果就会变成如下形式
// 方法名 迭代总次数 平均每次迭代时间 平均每次迭代分配字节数 平均每次迭代的内存分配次数
BenchmarkHello 2000000 898 ns/op 368 B/op 9 allocs/op
自定义度量值
ReportMetric(n float64, unit string)
汇报自定义度量值
- 如果度量值是每次迭代的,你应该将其除以
b.N
。 - 按照惯例,单位应该以 “/op” 结尾。
ReportMetric
会覆盖同一单位的任何先前报告的值。如果单位是空字符串,或者单位包含任何空格,ReportMetric
会引发 panic。- 如果单位是基准测试框架本身通常报告的单位(如 “allocs/op”),
ReportMetric
会覆盖该度量值。 - 将 “ns/op” 设置为 0 将禁止该内置度量值。
testing.Benchmark(func(b *testing.B) { var compares int64 for i := 0; i < b.N; i++ { s := []int{5, 4, 3, 2, 1} sort.Slice(s, func(i, j int) bool { compares++ return s[i] < s[j] }) } // This metric is per-operation, so divide by b.N and // report it as a "/op" unit. b.ReportMetric(float64(compares)/float64(b.N), "compares/op") // This metric is per-time, so divide by b.Elapsed and // report it as a "/ns" unit. b.ReportMetric(float64(compares)/float64(b.Elapsed().Nanoseconds()), "compares/ns") })
子测试
子测试也就是可以在测试中测试,子测试可以共用初始化等公共操作,并可以做父测试执行前的必要操作
func TestSubTest(t *testing.T) { t.Run("sub1", func(t *testing.T) { t.Log("sub1") }) t.Run("sub2", func(t *testing.T) { t.Log("sub2") }) t.Run("sub3", func(t *testing.T) { t.Log("sub3") }) }
模糊测试
模糊测试方法名为func FuzzXXX(f *testing.F)
func FuzzReverse(f *testing.F) { // 为模糊测试添加用例到种子语料库 testcases := []string{"Hello, world", " ", "!12345"} for _, tc := range testcases { f.Add(tc) // Use f.Add to provide a seed corpus } // 进行模糊测试。对于string类型的参数,将生成随机字符串 // 对于本测试中的Reverse方法是可逆的,因此可以通过两次逆行操作来验证其正确性 f.Fuzz(func(t *testing.T, orig string) { rev := Reverse(orig) doubleRev := Reverse(rev) if orig != doubleRev { t.Errorf("Before: %q, after: %q", orig, doubleRev) } if utf8.ValidString(orig) && !utf8.ValidString(rev) { t.Errorf("Reverse produced invalid UTF-8 string %q", rev) } }) }
运行模糊测试有go test
和go test -fuzz
两种方式,前者仅会运行手动添加的用例,而后者则会随机生成数据
值得注意的是如果go test -fuzz执行之后存在运行错误的用例会添加到语料库文件中,那么即使下次执行的是go test也依然会执行语料库文件中的用例
Ref
https://go.dev/doc/tutorial/fuzz
https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter09/09.0.html
到此这篇关于golang testing使用的文章就介绍到这了,更多相关golang testing使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!