0


【Go 快速入门】Go Test 工具 | 单元测试 | 基准测试

文章目录

本节项目地址:07-UnitTestBenchmarkTest

go test工具

Go语言中的测试依赖

go test

,该命令是一个按照一定约定和组织的测试代码的驱动程序。在包目录内,所有以

_test.go

为后缀名的源代码文件都是

go test

测试的一部分,不会被

go build

编译到最终的可执行文件中。

*_test.go

文件中有三种类型的函数,单元测试函数、基准测试函数和示例函数。
类型格式作用测试函数函数名前缀为

Test

测试程序的一些逻辑行为是否正确基准函数函数名前缀为

Benchmark

测试函数的性能示例函数函数名前缀为

Example

为文档提供示例文档

go test

命令会遍历所有的

*_test.go

文件中符合上述命名规则的函数,然后生成一个临时的

main

包用于调用相应的测试函数,然后构建并运行、报告测试结果,最后清理测试中生成的临时文件。

单元测试

  • 固定语法
func TestFuncName(t *testing.T) {}
  1. 单元测试的测试函数都以 Test 开头,可选的后缀名以大写字母开头
  2. 参数 t 是 *testing.T 类型,用于报告测试失败和附加的日志信息

下述创建了一个测试函数:

// TestStringSplit 测试 string 的 split 函数funcTestStringSplit(t *testing.T){// 定义一个测试用例类型type test struct{
        input string
        sep   string
        want  []string}// 定义一个存储测试用例的切片
    tests :=[]test{{input:"a:b:c", sep:":", want:[]string{"a","b","c"}},{input:"a:b:c", sep:",", want:[]string{"a:b:c"}},{input:"abcd", sep:"bc", want:[]string{"a","d"}},{input:"沙河有沙又有河", sep:"沙", want:[]string{"","河有","又有河"}},}// 遍历切片,逐一执行测试用例for_, tc :=range tests {
        got := strings.Split(tc.input, tc.sep)if!reflect.DeepEqual(got, tc.want){
            t.Errorf("expected:%#v, got:%#v", tc.want, got)}}}
  • go test -v:执行测试,并打印出测试函数名和运行时间
go test -v 
=== RUN   TestStringSplit
--- PASS: TestStringSplit (0.00s)
PASS
ok      07-UnitTestBenchmarkTest/UnitTest       0.662s

子测试

如果测试用例比较多的时候,我们是没办法一眼看出来具体是哪个测试用例失败了。可以按照如下方式使用

t.Run

执行子测试就能够看到更清晰的输出内容了。

// TestStringSplit1 测试 string 的 split 函数,子测试funcTestStringSplit1(t *testing.T){// 定义一个测试用例类型type test struct{
        input string
        sep   string
        want  []string}// 测试用例使用map存储
    tests :=map[string]test{"simple":{input:"a:b:c", sep:":", want:[]string{"a","b","c"}},"wrong sep":{input:"a:b:c", sep:",", want:[]string{"a:b:c"}},"more sep":{input:"abcd", sep:"bc", want:[]string{"a","d"}},"leading sep":{input:"沙河有沙又有河", sep:"沙", want:[]string{"河有","又有河"}},}for name, tc :=range tests {// 使用t.Run()执行子测试
        t.Run(name,func(t *testing.T){
            got := strings.Split(tc.input, tc.sep)if!reflect.DeepEqual(got, tc.want){
                t.Errorf("expected:%#v, got:%#v", tc.want, got)}})}}
go test -v 
=== RUN   TestStringSplit
--- PASS: TestStringSplit (0.00s)
=== RUN   TestStringSplit1
=== RUN   TestStringSplit1/wrong_sep
=== RUN   TestStringSplit1/more_sep
=== RUN   TestStringSplit1/leading_sep
    string_test.go:53: expected:[]string{"河有", "又有河"}, got:[]string{"", "河有", "又有河"}
=== RUN   TestStringSplit1/simple
--- FAIL: TestStringSplit1 (0.00s)
    --- PASS: TestStringSplit1/wrong_sep (0.00s)
    --- PASS: TestStringSplit1/more_sep (0.00s)
    --- FAIL: TestStringSplit1/leading_sep (0.00s)
    --- PASS: TestStringSplit1/simple (0.00s)
FAIL
exit status 1
FAIL    07-UnitTestBenchmarkTest/UnitTest       0.629s

如果指向执行指定的测试函数,可以通过

-run

参数指定,它对应一个正则表达式,只有函数名匹配的上的测试函数才会被

go test

命令执行。

go test -v -run=Split/simple
=== RUN   TestStringSplit
--- PASS: TestStringSplit (0.00s)
=== RUN   TestStringSplit1
=== RUN   TestStringSplit1/simple
--- PASS: TestStringSplit1 (0.00s)
    --- PASS: TestStringSplit1/simple (0.00s)
PASS
ok      07-UnitTestBenchmarkTest/UnitTest       0.046s

测试覆盖率

测试覆盖率是你的代码被测试套件覆盖的百分比。通常我们使用的都是语句的覆盖率,也就是在测试中至少被运行一次的代码占总代码的比例。

Go提供内置功能来检查你的代码覆盖率。我们可以使用

go test -cover

来查看测试覆盖率。Go还提供了一个额外的

-coverprofile

参数,用来将覆盖率相关的记录信息输出到一个文件。

使用:

go test -cover -coverprofile="a.out"

,将会生成

a.out

文件。然后可以执行

go tool cover -html="a.out"

,使用

cover

工具来处理生成的记录信息,该命令会打开本地的浏览器窗口生成一个

HTML

报告。


基准测试

  • 固定语法
func BenchmarkFuncName(b *testing.B) {}
  1. 基准测试的测试函数都以 Benchmark 开头
  2. 参数 b 是 *testing.B 类型
  3. 基准测试必须包含for循环,循环次数是 b.N 次(b.N的值是系统根据实际情况调整,保证测试稳定性)

下述创建了一个测试函数:

funcsplit(s, sep string)(result []string){
    result =make([]string,0, strings.Count(s, sep)+1)
    i := strings.Index(s, sep)for i >-1{
        result =append(result, s[:i])
        s = s[i+len(sep):]
        i = strings.Index(s, sep)}
    result =append(result, s)return}// BenchmarkSplit 测试自定义的 split 函数funcBenchmarkSplit(b *testing.B){for i :=0; i < b.N; i++{split("沙河有沙又有河","沙")}}

使用

go test -v -bench=Split

命令执行基准测试,基础测试默认不会执行,必须携带

-bench

参数。

go test -v -bench=Split
goos: windows
goarch: amd64
pkg: 07-UnitTestBenchmarkTest/BenchmarkTest
cpu: 13th Gen Intel(R) Core(TM) i9-13900HX
BenchmarkSplit
BenchmarkSplit-32       26486323                47.05 ns/op
PASS
ok      07-UnitTestBenchmarkTest/BenchmarkTest  1.897s

其中

BenchmarkSplit-32

表示对 Split 函数进行基准测试,数字

32

表示

GOMAXPROCS

的值,

26486323

47.05 ns/op

表示每次调用 Split 函数耗时

47.05ns

,这个结果是

26486323

次调用的平均值。

还可以为基准测试添加

-benchmem

参数,来获得内存分配的统计数据。如下所示,

48 B/op

表示每次操作内存分配了48字节,

1 allocs/op

表示每次操作进行了1次内存分配。

go test -v -bench=Split -benchmem
goos: windows
goarch: amd64
pkg: 07-UnitTestBenchmarkTest/BenchmarkTest
cpu: 13th Gen Intel(R) Core(TM) i9-13900HX
BenchmarkSplit
BenchmarkSplit-32       26387544                45.29 ns/op           48 B/op          1 allocs/op
PASS
ok      07-UnitTestBenchmarkTest/BenchmarkTest  1.295s

性能比较函数

性能比较函数通常是一个带有参数的函数,被多个不同的

Benchmark

函数传入不同的值来调用。

funcfib(n int)int{if n <2{return n
    }returnfib(n-1)+fib(n-2)}funcbenchmarkFib(b *testing.B, n int){for i :=0; i < b.N; i++{fib(n)}}funcBenchmarkFib1(b *testing.B){benchmarkFib(b,1)}funcBenchmarkFib2(b *testing.B){benchmarkFib(b,2)}funcBenchmarkFib3(b *testing.B){benchmarkFib(b,3)}funcBenchmarkFib10(b *testing.B){benchmarkFib(b,10)}funcBenchmarkFib20(b *testing.B){benchmarkFib(b,20)}funcBenchmarkFib40(b *testing.B){benchmarkFib(b,40)}

上述编写了一个斐波那契数列计算函数,并在不同大小的n值的情况下进行基准测试。

go test -v -bench=Fib          
goos: windows
goarch: amd64
pkg: 07-UnitTestBenchmarkTest/BenchmarkTest
cpu: 13th Gen Intel(R) Core(TM) i9-13900HX
BenchmarkFib1
BenchmarkFib1-32        1000000000               0.5479 ns/op
BenchmarkFib2
BenchmarkFib2-32        736555106                1.600 ns/op
BenchmarkFib3
BenchmarkFib3-32        459925009                2.590 ns/op
BenchmarkFib10
BenchmarkFib10-32        7295648               164.5 ns/op
BenchmarkFib20
BenchmarkFib20-32          59763             20160 ns/op
BenchmarkFib40
BenchmarkFib40-32              4         306910725 ns/op
PASS
ok      07-UnitTestBenchmarkTest/BenchmarkTest  8.692s

默认情况下,每个基准测试至少运行1秒,可以通过参数

-benchtime

设置基准测试时间。此外还有

-cpu

参数设置运行基准测试的并发数,

-count

参数设置运行测试的总次数。

go test -v -bench="." -benchtime=2s 
goos: windows
goarch: amd64
pkg: 07-UnitTestBenchmarkTest/BenchmarkTest
cpu: 13th Gen Intel(R) Core(TM) i9-13900HX
BenchmarkSplit
BenchmarkSplit-32       48237133                44.58 ns/op
BenchmarkFib1
BenchmarkFib1-32        1000000000               0.5392 ns/op
BenchmarkFib2
BenchmarkFib2-32        1000000000               1.575 ns/op
BenchmarkFib3
BenchmarkFib3-32        931792406                2.590 ns/op
BenchmarkFib10
BenchmarkFib10-32       14704368               163.8 ns/op
BenchmarkFib20
BenchmarkFib20-32         119018             20080 ns/op
BenchmarkFib40
BenchmarkFib40-32              7         303590871 ns/op
PASS
ok      07-UnitTestBenchmarkTest/BenchmarkTest  14.857s

重置时间

b.ResetTimer

之前的处理不会放到执行时间里,也不会输出到报告中,所以可以在之前做一些不计划作为测试报告的操作。

b.ReportAllocs()

记录内存分配数据。

funcBenchmarkResetTimer(b *testing.B){
    time.Sleep(3* time.Second)
    b.ResetTimer()
    b.ReportAllocs()for i :=0; i < b.N; i++{split("abc.poe.org.com",".")}}
go test -bench="Timer"
goos: windows
goarch: amd64
pkg: 07-UnitTestBenchmarkTest/BenchmarkTest
cpu: 13th Gen Intel(R) Core(TM) i9-13900HX
BenchmarkResetTimer-32          32262052                34.99 ns/op           64 B/op          1 allocs/op
PASS
ok      07-UnitTestBenchmarkTest/BenchmarkTest  16.843s

并行测试

func (b *B) RunParallel(body func(*PB))

会以并行的方式执行给定的基准测试。

RunParallel

会创建出多个

goroutine

,并将

b.N

分配给这些

goroutine

执行, 其中

goroutine

数量的默认值为

GOMAXPROCS

。用户如果想要增加非

CPU

受限

(non-CPU-bound)

基准测试的并行性, 那么可以在

RunParallel

之前调用

SetParallelism

RunParallel

通常会与

-cpu

标志一同使用。

funcBenchmarkSplitParallel(b *testing.B){// b.SetParallelism(1) // 设置使用的cpu数
    b.RunParallel(func(pb *testing.PB){for pb.Next(){split("cn.com.org",".")}})}
go test -bench="Parallel" -cpu=4
goos: windows
goarch: amd64
pkg: 07-UnitTestBenchmarkTest/BenchmarkTest
cpu: 13th Gen Intel(R) Core(TM) i9-13900HX
BenchmarkSplitParallel-4        95221719                14.72 ns/op
PASS
ok      07-UnitTestBenchmarkTest/BenchmarkTest  2.329s

参考:https://www.liwenzhou.com/posts/Go/unit-test/


本文转载自: https://blog.csdn.net/qq_52678569/article/details/141786689
版权归原作者 ღCauchyོꦿ࿐ 所有, 如有侵权,请联系我们删除。

“【Go 快速入门】Go Test 工具 | 单元测试 | 基准测试”的评论:

还没有评论