Golang测试用例test

Go语言中自带有一个轻量级的测试框架testing和自带的go test命令来实现单元测试和性能测试。这里以main_test.go这个文件为例

1. 单元测试文件,基本原则:

文件名必须是_test.go结尾的,这样在执行go test的时候才会执行到相应的代码
你必须import testing这个包
所有的测试用例函数必须是Test开头
测试用例会按照源代码中写的顺序依次执行
测试函数TestXxx()的参数是testing.T,我们可以使用该类型来记录错误或者是测试状态
测试格式:func TestXxx (t *testing.T),Xxx部分可以为任意的字母数字的组合,但是首字母不
是小写字母[a-z],例如Testintdiv是错误的函数名。
函数中通过调用testing.T的Error, Errorf, FailNow, Fatal, FatalIf方法,说明测试不通过,调用Log方法用来记录测试的信息。

2. 功能测试函数

2.1 测试函数中的某条测试用例执行结果与预期不符时,调用t.Error()或t.Errorf()方法记录日志并标记测试失败:

func TestCompareIdenticalSlice(t *testing.T) {
sa := "aaa"
sb := "bbb"
if strings.Compare(sa, sb) != 0 {
    t.Error("b != b")
    }
}

2.2 使用t.Fatal()和t.Fatalf()方法,在某条测试用例失败后就跳出该测试函数

func TestCompareIdenticalSlice(t *testing.T) {
sa := "aaa"
sb := "bbb"
if strings.Compare(sa, sb) != 0 {
    t.Fatal("error")
}

s1 := "aaa1"
s2 := "bbb"
if strings.Compare(s1, s2) != 0 {
    t.Errorf("errorf")
    }
}

2.3 使用t.Skip()和t.Skipf()方法,跳过某条测试用例的执行如下会跳过TestCompareIdenticalSlice 执行 TestCompareIdenticalSlice1测试用例

func TestCompareIdenticalSlice(t *testing.T) {

    sa := "aaa"
    sb := "bbb"
    if strings.Compare(sa, sb) != 0 {
        t.Skip("slow test; skipping")
    }

    s1 := "aaa1"
    s2 := "bbb"
    if strings.Compare(s1, s2) != 0 {
        t.Errorf("errorf")
    }
}
func TestCompareIdenticalSlice1(t *testing.T) {

    sa := "aaa"
    sb := "bbb"
    if strings.Compare(sa, sb) != 0 {
        t.Errorf("errorf2")
    }

    s1 := "bbb"
    s2 := "bbb"
    if strings.Compare(s1, s2) != 0 {
        t.Errorf("errorf2")
    }

}

2.4 使用t.Parallel()标记需要并发执行的测试函数

func gorw() {
    sa := "aaa"
    sb := "bbb"
    if strings.Compare(sa, sb) != 0 {
        fmt.Println("dfdf")
    }
}
func TestCompareIdenticalSlice(t *testing.T) {
    t.Parallel()
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        defer wg.Done()
        gorw()
    }()
    wg.Wait()

}

sync.WaitGroup只有3个方法,Add(),Done(),Wait()。其中Done()是Add(-1)的别名。简单的来说,使用Add()添加计数,Done()减掉一个计数,计数不为0, 阻塞Wait()的运行。

要注意的有一点。sync文档已经说明了的,The main goroutine calls Add to set the number of goroutines to wait for. Then each of the goroutines runs and calls Done when finished.也就是说,在运行main函数的goroutine里运行Add()函数,在其他的goroutine里面运行Done()函数。

3. 性能测试函数

性能测试函数需要接收*testing.B类型的单一参数b,性能测试函数中需要循环b.N次调用被测函数。testing.B 类型用来管理测试时间和迭代运行次数,也支持和testing.T相同的方式管理测试状态和格式化的测试日志,不一样的是testing.B的日志总是会输出。

3.1 在函数中调用t.ReportAllocs() ,启用内存使用分析

func BenchmarkCompareIdenticalSlice(b *testing.B) {
    b.ReportAllocs()
    sa := "aaa"
    sb := "bbb"
    if strings.Compare(sa, sb) != 0 {
        fmt.Println("dfdf")
    }

}

3.2 通过 b.StopTimer() 、b.ResetTimer() 、b.StartTimer()来停止、重置、启动 时间经过和内存分配计数

    func BenchmarkCompareIdenticalSlice(b *testing.B) {
        b.ResetTimer()
        b.StartTimer()
        for i := b.N - 1; i >= 0; i-- {

            fmt.Println(i)

        }
        b.StopTimer()
}

3.3 调用b.SetBytes()记录在一个操作中处理的字节数,最终会显示执行的次数,每次执行所用时间ns/op 以及MB/s

func BenchmarkCompareIdenticalSlice(b *testing.B) {
        b.SetBytes(int64(len("fieldsInput")))
        for i := 0; i < b.N; i++ {
            fmt.Println("fieldsInput")
        }
}

3.4 通过b.RunParallel()方法和 *testing.PB类型的Next()方法来并发执行被测对象,最终会显示执行的次数,每次执行所用时间ns/op

func BenchmarkCompareIdenticalSlice(b *testing.B) {
    var v atomic.Value
    v.Store(new(int))
    b.RunParallel(func(pb *testing.PB) {
        for pb.Next() {
            x := v.Load().(*int)
            if *x != 0 {
                b.Fatalf("wrong value: got %v, want 0", *x)
            }
        }
    })
}

4. go test 工具

打开终端,进入需要测试的包所在的目录执行 go test,或者直接执行go test $pkgnamein_gopath即可对指定的包执行测试。通过形如go test github.com/tabalt/...的命令可以执行$GOPATH/github.com/tabalt/目录下所有的项目的测试。go test std命令则可以执行Golang标准库的所有测试。

4.1 如果想查看执行了哪些测试函数及函数的执行结果,可以使用-v参数:

E:\GoWorks>go test -v
=== RUN   TestCompareIdenticalSlice
--- FAIL: TestCompareIdenticalSlice (0.00s)
    main_test.go:27: sa != sb
FAIL
exit status 1
FAIL    _/E_/GoWorks    0.094s

4.2 假设我们有很多功能测试函数,但某次测试只想执行其中的某一些,可以通过-run参数,使用正则表达式来匹配要执行的功能测试函数名。如下面指定参数后,功能测试函数TestHello不会执行到。

E:\GoWorks>go test -v -run="TestCompareIdenticalSlice"
=== RUN   TestCompareIdenticalSlice
--- FAIL: TestCompareIdenticalSlice (0.00s)
        main_test.go:27: sa != sb
FAIL
exit status 1
FAIL    _/E_/GoWorks    0.090s

4.3 性能测试函数默认并不会执行,需要添加-bench参数,并指定匹配性能测试函数名的正则表达式;例如,想要执行某个包中所有的性能测试函数可以添加参数-bench . 或 -bench=.,如果执行指定的性能测试函数参数为 -bench="BenchXXX"。

    (1) E:\GoWorks>go test -bench=.
    BenchmarkCompareIdenticalSlice-8        1000000000               2.46 ns/op
    PASS
    ok      _/E_/GoWorks    2.789s
    (2) E:\GoWorks>go test -bench=BenchmarkCompareIdenticalSlice2
    BenchmarkCompareIdenticalSlice2-8       1000000000               2.33 ns/op
    PASS
    ok      _/E_/GoWorks    2.577s

4.4 想要查看性能测试时的内存情况,可以再添加参数-benchmem:

E:\GoWorks>go test -bench="BenchmarkCompareIdenticalSlice2" -benchmem
BenchmarkCompareIdenticalSlice2-8       1000000000               2.47 ns/op            0 B/op          0 allocs/op
PASS
ok      _/E_/GoWorks    2.800s

5. 通过go help test可以看到go test的使用说明:

格式形如:
go test [-c] [-i] [build flags] [packages] [flags for test binary]

参数解读:
1. -c : 编译go test成为可执行的二进制文件,但是不运行测试。
2. -i : 安装测试包依赖的package,但是不运行测试。

关于build flags,调用go help build,这些是编译运行过程中需要使用到的参数,一般设置为空

关于packages,调用go help packages,这些是关于包的管理,一般设置为空

关于flags for test binary,调用go help testflag,这些是go test过程中经常使用到的参数
3. -test.v : 是否输出全部的单元测试用例(不管成功或者失败),默认没有加上,所以只输出失败的单元测试用例。

E:\GoWorks>go test -v

4 -test.run pattern: 只跑哪些单元测试用例 :

E:\GoWorks>go test -run="TestCompareIdenticalSlice"

5 -test.bench patten: 只跑那些性能测试用例

E:\GoWorks> go test -bench="."

6 -test.benchmem : 是否在性能测试的时候输出内存情况:

E:\GoWorks> go test -bench="BenchmarkCompareIdenticalSlice2" -benchmem

7 -test.benchtime t : 性能测试运行的时间,默认是1s

8 -test.cpuprofile cpu.out : 是否输出cpu性能分析文件

E:\GoWorks>go test -run = "main_test.go" -cpuprofile cpu.out

9 -test.memprofile mem.out : 是否输出内存性能分析文件

E:\GoWorks> go test -run = "main_test.go" -memprofile mem.out

10 -test.blockprofile block.out : 是否输出内部goroutine阻塞的性能分析文件

E:\GoWorks> go test -run = "main_test.go" -blockprofile mem.out

11 -test.memprofilerate n : 内存性能分析的时候有一个分配了多少的时候才打点记录的问题。这个参数就是设置打点的内存分配间隔,也就是profile中一个sample代表的内存大小。默认是设置为512 * 1024的。如果你将它设置为1,则每分配一个内存块就会在profile中有个打点,那么生成的profile的sample就会非常多。如果你设置为0,那就是不做打点了。

你可以通过设置memprofilerate=1和GOGC=off来关闭内存回收,并且对每个内存块的分配进行观察。

12 -test.blockprofilerate n: 基本同上,控制的是goroutine阻塞时候打点的纳秒数。默认不设置就相当于-test.blockprofilerate=1,每一纳秒都打点记录一下

13 -test.parallel n : 性能测试的程序并行cpu数,默认等于GOMAXPROCS。

14 -test.timeout t : 如果一个测试运行的时间超过t,那么panic。 默认值是10分钟(1000米)。

E:\GoWorks>go test -run="main_test.go"  -timeout 1000s

15 -test.count n: 运行每个测试和基准测试n次(默认1)。 如果-cpu被设置,则为每个GOMAXPROCS值运行n次。 示例总是运行一次。

E:\GoWorks>go test -bench="BenchmarkCompareIdenticalSlice2" -count=10

16 -test.cpu 1,2,4 : 程序运行在哪些CPU上面,使用二进制的1所在位代表,和nginx的nginxworkercpu_affinity是一个道理

17 -test.short : 将那些运行时间较长的测试用例运行时间缩短

E:\GoWorks>go test -run="main_test.go"  -short=false  

18 -outputdir directory: 将输出文件从指定目录的概要文件中放置

E:\GoWorks>go test -bench="BenchmarkCompareIdenticalSlice2"  -test.blockprofile block.out   -outputdir="E:/GoWorks/data"

19 -trace trace.out : 关于执行跟踪向文件中写入指定在退出之前

E:\GoWorks>go test -bench="BenchmarkCompareIdenticalSlice2" -trace trace.out  

20 -test.memprofilerate rate:设置内存分析率(见运行时)

21 -test.mutexprofile string:在执行后将一个互斥锁争用配置文件写入到指定的文件中

22 -test.mutexprofilefraction int :如果大于0,则调用runtime.setmutexprofile分式()

你可能感兴趣的:(golang)