31

使用 Go 进行单元测试

 4 years ago
source link: https://studygolang.com/articles/24507
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

简介

日常开发中, 测试是不能缺少的.

Go 标准库中有一个叫做 testing 的测试框架, 可以用于单元测试和性能测试.

它是和命令 go test 集成使用的.

测试文件是以后缀 _test.go 命名的, 通常和被测试的文件放在同一个包中.

单元测试

单元测试的格式形如:

func TestAbs(t *testing.T) {
  got := Abs(-1)
  if got != 1 {
    t.Errorf("Abs(-1) = %d; want 1", got)
  }
}

util 目录下创建一个文件 util_test.go , 添加一个单元测试:

package util

import "testing"

// 普通的测试
func TestGenShortID(t *testing.T) {
    shortID, err := GenShortID()
    if shortID == "" || err != nil {
        t.Error("GenShortID failed")
    }
}

然后, 在根目录下运行 go test -v ./util/ , 测试结果如下:

root@592402321ce7:/workspace# go test -v ./util/
=== RUN   TestGenShortID
--- PASS: TestGenShortID (0.00s)
PASS
ok      tzh.com/web/util        0.006s

性能测试

性能测试的结果形如:

func BenchmarkHello(b *testing.B) {
  for i := 0; i < b.N; i++ {
    fmt.Sprintf("hello")
  }
}

util_test.go 添加性能测试:

// 性能测试
func BenchmarkGenShortID(b *testing.B) {
    for i := 0; i < b.N; i++ {
        GenShortID()
    }
}

运行结果如下(使用 --run=none 避免运行普通的测试函数, 因为一般不可能有函数名匹配 none ):

root@592402321ce7:/workspace# go test -v -bench="BenchmarkGenShortID$" --run=none ./util/
goos: linux
goarch: amd64
pkg: tzh.com/web/util
BenchmarkGenShortID-2             507237              2352 ns/op
PASS
ok      tzh.com/web/util        1.229s

这说明, 平均每次运行 GenShortID() 需要 2352 纳秒.

性能分析

运行测试的时候, 可以指定一些参数, 生成性能文件 profile.

-blockprofile block.out
    Write a goroutine blocking profile to the specified file
    when all tests are complete.
    Writes test binary as -c would.

-blockprofilerate n
    Control the detail provided in goroutine blocking profiles by
    calling runtime.SetBlockProfileRate with n.
    See 'go doc runtime.SetBlockProfileRate'.
    The profiler aims to sample, on average, one blocking event every
    n nanoseconds the program spends blocked. By default,
    if -test.blockprofile is set without this flag, all blocking events
    are recorded, equivalent to -test.blockprofilerate=1.

-coverprofile cover.out
    Write a coverage profile to the file after all tests have passed.
    Sets -cover.

-cpuprofile cpu.out
    Write a CPU profile to the specified file before exiting.
    Writes test binary as -c would.

-memprofile mem.out
    Write an allocation profile to the file after all tests have passed.
    Writes test binary as -c would.

-memprofilerate n
    Enable more precise (and expensive) memory allocation profiles by
    setting runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
    To profile all memory allocations, use -test.memprofilerate=1.

-mutexprofile mutex.out
    Write a mutex contention profile to the specified file
    when all tests are complete.
    Writes test binary as -c would.

-mutexprofilefraction n
    Sample 1 in n stack traces of goroutines holding a
    contended mutex.

使用下面的命令, 生成 CPU 的 profile:

go test -v -bench="BenchmarkGenShortID$" --run=none -cpuprofile cpu.out ./util/

当前目录下, 应该会生成 cpu.out 文件和 util.test 文件.

使用下面的命令, 观察耗时操作:

# 进入交互模式
go tool pprof cpu.out
top

安装 Graphviz 后可以生成可视化的分析图.

apt install graphviz
go tool pprof -http=":" cpu.out

测试覆盖率

root@592402321ce7:/workspace# go test -v -coverprofile=cover.out ./util/
=== RUN   TestGenShortID
--- PASS: TestGenShortID (0.00s)
PASS
coverage: 9.1% of statements
ok      tzh.com/web/util        0.005s  coverage: 9.1% of statements

root@592402321ce7:/workspace# go tool cover -func=cover.out
tzh.com/web/util/util.go:12:    GenShortID      100.0%
tzh.com/web/util/util.go:17:    GetReqID        0.0%
tzh.com/web/util/util.go:22:    TimeToStr       0.0%
tzh.com/web/util/util.go:30:    GetTag          0.0%
total:                          (statements)    9.1%

使用 -coverprofile=cover.out 选项可以统计测试覆盖率.

使用 go tool cover -func=cover.out 可以查看更加详细的测试覆盖率结果,

统计每个函数的测试覆盖率.

总结

测试是开发中非常重要的一个环节, 用于保证软件质量, 切不可偷懒.

当前部分的代码

作为版本 v0.15.0


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK