golang 单元测试 (https://github.com/stayfoo/stayfoo-hub)

我的 golang 开发笔记:https://github.com/stayfoo/stayfoo-hub

单元测试

一般有三类测试:功能测试(test)、性能测试(benchmark,也叫基准测试)、示例测试(example)。

编写规则

测试源码文件名称要求: 被测试源码文件的名称_test.go , eg:要对 demo.go 进行测试,测试文件就是 demo_test.go

测试函数的名称和签名规定:

  • test 测试函数,名称必须以 Test 为前缀; 只能有一个参数, 且参数类型: *testing.T
  • benchmark 测试函数,名称必须以 Benchmark 为前缀; 只能有一个参数,且类型为: *testing.B
  • example 测试函数, 名称必须以 Example 为前缀;对参数列表没有强制规定。(与功能测试相比,更关注程序打印出来的内容)

go test

go test 使测试代码执行,需要测试文件编写遵循上面的规则。

go test 执行的主要流程:

=== RUN   TestFail
--- PASS: TestFail (0.00s)
    main_test.go:49: Failed.
PASS
ok      code/test       0.006s

# ok: 说明测试结果和预期一样
# code/test: 测试的代码包路径
# 0.006s : 此次对该代码包的测试所耗费的时间
  • 参数 -run
#执行被测试包中的所有功能测试函数
go test
#同 go test
go test -run ''

#可以是一个函数的名字
go  test -run=TestHello

#匹配部分函数名, 匹配以 TestHel 开头的测试函数, eg: TestHello
go  test -run=Hel
#同上
go test -run Hel

不执行任何功能测试函数 -run ^$

go test -run ^$

# 和其他参数一起使用,比如只想执行 benchmark 函数:
go test -run ^$ -bench .

测试代码:

func TestHello2(t *testing.T) {
	t.Run("A=1", func(t *testing.T) {
		fmt.Println("hello2 is A=1")
	})
	t.Run("A=2", func(t *testing.T) {
		fmt.Println("hello2 is A=2")
	})
	t.Run("B=1", func(t *testing.T) {
		fmt.Println("hello2 is B=1")
	})
}
# 匹配运行 所有 TestHello 开头的测试函数,以及测试函数内部 A= 的子测试用例
go test -run Hello/A=

# 匹配运行 所有的测试函数,以及测试函数内部 A=1 的子测试用例
go test -run /A=1
  • 缓存:
# 查看缓存目录的路径:
go env GO CACHE 

# 手动删除所有缓存
go clean -cache

# 删除所有的测试结果缓存;不会删除任何构建结果缓存。
go clean -testcache
#设置环境变量 GODEBUG
# go 命令绕过任何的缓存数据,真正执行操作并重新生成所有结果,然后再去检查新的结果与现有的缓存数据是否一致
gocacheverify=1

Benchmark

go test 加上 -bench=. 才会执行性能测试。

# 值 . 表示执行任意名称的性能测试函数
go test -bench=.

还可以是一个函数的名字 或者前面一部分:
go  test -bench=BenchmarkGetStore
go  test -bench=BenchmarkGetS
  • 只执行 Benchmark
# 和其他参数一起使用,比如只想执行 benchmark 函数:
go test -run ^$ -bench .
  • 运行结果解读
func BenchmarkHandleData(b *testing.B)  {
	for i:=0; i<b.N; i++ {
		HandleData()
	}
}
go test -run ^$ -bench .

goos: darwin
goarch: amd64
BenchmarkHandleData-4        3000            401651 ns/op
PASS
ok      command-line-arguments  1.259s
#1. 运行的性能测试函数:BenchmarkHandleData  被测试的函数是:HandleData
#2. 运行时使用的最大 P 数量为 4
#3. 3000 是指被测函数 HandleData 的执行次数
#4. 401651 ns/op = 性能测试函数执行时间 / 被测函数执行次数; 单次执行被测函数的平均耗时为 401651 纳秒;
BenchmarkHandleData-4        3000            401651 ns/op

最大 P 数量 ?

P:processor ,是 G 和 M的中介,使 G 与 M 对接并得到真正的运行。Go运行时系统中,P越多,承载 G 的队列越多, G可运行的越多(最大P代表同时运行goroutine的能力)。 每一条承载 G 的队列,会不断的把可运行的 G 给空闲的 M 去对接。对接完成,被对接的 G 就真正运行在操作系统的内核级线程上了。每条队列之间会有联系,但都是独立运作的。

G: goroutine ,协程

M: machine ,代表着系统级线程,即操作系统内核级别的线程

使用 go test -cpu 来设置最大 P 数量. 或者 调用 runtime.GOMAXPROCS 函数改变最大 P 数量。模拟被测试程序在不同计算能力的计算机中的表现。

一些函数

t.Log()

打印常规的测试日志:(当测试成功的时候,不会打印)

t.Log()
t.Logf()

可以使用 -v 打印所有的常规测试日志:

go test -v

t.Fail()

func TestFail(t *testing.T) {
	t.Fail()
	//t.FailNow() //会让函数立即终止,该行代码之后的所有代码都不会执行。
	t.Log("Failed.")
}

对于失败测试的结果, go test 命令并不会进行缓存。 测试失败,会把失败函数里面的常规日志打印出来。( t.Log("Failed.")

t.Error()

t.Error() 相当于 t.Fail() + t.Log()

//相当于 t.Fail() + t.Log("Failed log.")
t.Error("Failed log.")

t.Errorf() 相当于 t.Fail() + t.Logf()

//相当于 t.Fail() + t.Log("Failed log.")
t.Errorf("Failed log.")

t.Fatal()

打印失败错误日志之后立即终止当前测试函数的执行,测试失败。

相当于最后调用了 t.FailNow()

t.Fatal("Failed log.")
t.Fatalf("Failed log.")

我的 golang 开发笔记:https://github.com/stayfoo/stayfoo-hub

我来评几句
登录后评论

已发表评论数()

相关站点

热门文章