博客 记录生活,记录工作。

Golang单元测试和性能测试

2017-12-06
go
 

1. 引言

Go提供了go test命令来进行单元测试和性能测试。测试命令的格式如下,

go test [build/test flags] [packages] [build/test flags & test binary flags]

当我们使用go test的时候,测试文件需要满足一些规则:

  1. 文件名必须以_test.go结尾
  2. 必须引入测试包,即import testing

下面我们简单介绍几个test flags,如下表所示,

命令 意义 示例
-bench regexp 只执行匹配正则表达式的benchmark -bench=. // 匹配所有
-count n 执行n次unit test和benchmark,默认为1次 -count=5
-cover 开启覆盖率分析  
-run regexp 只执行匹配正则表达式的测试  
-v 长格式输出,输出完整的测试信息  
-cpuprofile cpu.out 执行结束前生成cpu profile文件  
-timeout d 执行时间超过d会panic,默认10min  
-benchmem 为benchmark开启内存分配分析  

2. 单元测试

单元测试中测试函数的格式如下,

func TestXxx(t *testing.T)

另外,单元测试函数需满足以下规则:

  1. 测试用例函数必须是Test开头,TestXxx()的参数是*testing.T
  2. Xxx部分可以为任意的字母数字的组合,但是首字母不能是小写字母(可以下划线)
  3. 测试函数中通过调用testing.TError, Errorf, FailNow, Fatal, Fatalf方法,说明测试不通过,调用Log方法用来记录测试的信息。

最后直接在测试文件所在包中执行下面命令,即可执行包中所有的测试例,

# $ go test -v #详细显示测试结果
# $ go test file.go file_test.go #测试文件file_test.go
$ go test # 测试包中所有测试例

下面我们从具体例子来进行单元测试,首先创建我们待测试的功能模块–提供除法的功能函数,

package gotest

import (
    "errors"
)

func Division(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("除数不能为0")
    }

    return a / b, nil
}

再次,我们创建单元测试文件如下,

package gotest

import "testing"

func TestDivision1(t *testing.T) {
    if i, e := Division(6, 2); i != 3 || e != nil {
        t.Error("Division test fail")   
    } else {
        t.Log("Division test success")
    }
}

func TestDivision2(t *testing.T) {
    t.Log("Division test success")
}

最后我们执行单元测试命令,

$ go test sample/gotest
ok      sample/gotest   0.006s

$ go test sample/gotest -v
=== RUN   TestDivision1
--- PASS: TestDivision1 (0.00s)
    gotest_test.go:9: Division test success
=== RUN   TestDivision2
--- PASS: TestDivision2 (0.00s)
    gotest_test.go:14: Division test success
PASS
ok      sample/gotest   0.008s

当我们更改单元测试函数如下时,

func TestDivision2(t *testing.T) {
    t.Error("Division test fail")
}

执行结果如下,

$ go test sample/gotest
--- FAIL: TestDivision2 (0.00s)
    gotest_test.go:14: Division test fail
FAIL
FAIL    sample/gotest   0.007s

$ go test sample/gotest -v
=== RUN   TestDivision1
--- PASS: TestDivision1 (0.00s)
    gotest_test.go:9: Division test success
=== RUN   TestDivision2
--- FAIL: TestDivision2 (0.00s)
    gotest_test.go:14: Division test fail
FAIL
exit status 1
FAIL    sample/gotest   0.007s

3. 性能测试

性能测试函数的格式如下,

func BenchmarkXxx(b *testing.B)

压力测试函数规则:

  1. 测试用例函数必须是Benchmark开头,BenchmarkXxx()的参数是*testing.B
  2. Xxx可以是任意字母数字的组合,但是首字母不能是小写字母
  3. 压力测试用例中,需在循环体内使用testing.B.N,
#go test -run=regexp -bench=regexp -cpuprofile=profile -count n package
go test -run=benchmark_test.go -bench=BenchmarkDivision1 -count=5 -cpuprofile=cpuprofile.file sample/gotest

针对性能测试,如下例所示,

package gotest

import (
    "testing"
)

func BenchmarkDivision1(b *testing.B) {
    for i := 0; i < b.N; i++ { 
        Division(4, 5)
    }
}

func BenchmarkDivision2(b *testing.B) {
    b.StopTimer() //stop time
    //do some init
    b.StartTimer() //start time
    for i := 0; i < b.N; i++ {
        Division(4, 5)
    }
}

执行结果如下,

$ go test -run=benchmark_test.go -bench=. sample/gotest
goos: darwin
goarch: amd64
pkg: sample/gotest
BenchmarkDivision1-4    2000000000           0.87 ns/op
BenchmarkDivision2-4    2000000000           0.88 ns/op
PASS
ok      sample/gotest   3.699s

当我们使用-cpuprofile=xxx,会生成性能分析文件,针对profile文件的分析请查看下篇pprof文章。


相关博文

上一篇 JSON and Go

下一篇 Go类型断言

评论