这书是之前CU(chinaunix.net)论坛。搞活动得到奖品(还有作者亲笔签名),拿回来都没看完.
因为写得太太太细了,又厚。
参考他的书及官网的文档,再把测试方面的东西过一下还是有点意思的.
这篇主要讲这几点:
一.Testing的几种不同形式
功能测试:
TestXxxx(t *testing.T)
基准测试:
BenchmarkXxxx(b *testing.B)
样本测试:
Example_Xxx()
用于测试的Main函数:
TestMain(m *testing.M)
//
// func TestMain(m *testing.M) {
// flag.Parse()
// os.Exit(m.Run())
// }
二. 测试中的资源收集
三. 测试覆盖率
一.Testing的几种不同形式
功能测试:
TestXxxx(t *testing.T)
偏向于测试某个源码文件中的具体源码功能实现。
基本是在同一个包位置。
go test 来运行.
//运行包下的所有测试
go test -v prj/pkg
//只测试这个包下名称与之匹配的功能测试函数
go test -v -run=xxfunc prj/pkg
控制测试运行时间:
-timeout : 超时控制
go test -timeout 100ms prj/pkg //可以用1h20s之类表示时间
(时间单位: h小时/m分钟/s秒/ms毫秒/us微秒/ns纳秒)
-short : 是否缩短测试时间
可以在测试代码中加上这个if
if testing.Short() {
}else{
}
然后在运行命令中加上 -short参数,如:
go test -short prj/pkg
并发控制:
测试函数默认是不并发执行的.如要并发执行.除了设置GOMAXPROCS外,
runtime.GOMAXPROCS( runtime.NumCPU())
还要在要测试的函数中开始,加上
t.Parallel()
func TestParallel(t *testing.T){
t.Parallel()
//......
}
go test -parallel 8
基准测试:
BenchmarkXxxx(b *testing.B)
运行:
go test benxxx_test.go -bench="."
go test -bench=xxfunc
go test -bench=xxfunc prj/pkg
Go的Benchmark默认是在1s的时间内,尽可能多的执行这个函数. 可以通过 -benchtime 这个参数扩大时长.
go test benxxx_test.go -benchtime=2s
标准包中的相关源码:
var benchTime = flag.Duration("test.benchtime", 1*time.Second, "approximate run time for each benchmark") // Run the benchmark for at least the specified amount of time. d := *benchTime for !b.failed && b.duration < d && n < 1e9 {
测试函数模板例子:
func BenchmarkXxxx(b *testing.B){ var ( //初始化 ) b.StopTimer() //停止测试计时,因为默认是打开计时的. //////////////////////////////// // 一些不需要计入测试时间的动作 // ...... //////////////////////////////// b.StartTimer() //开始测试计时 //////////////////////////////// // 继续运行测试 // 如: for i:=0;i<b.N;i++{ //...... } //////////////////////////////// // 如有重置计数时间需求 // RestTimer() 把之前累计的函数执行时间重置成0 // 继续运行测试 // ........ }
Benchmark 与功能测试不同的地方在于,它更多的关注性能之类的指标上.
例子:
package main import ( "fmt" "testing" ) func BenchmarkXxxx(b *testing.B) { for i := 0; i < b.N; i++ { fmt.Println("i:", i) } }测试结果:
30000 50806 ns/op
ok _/E_/GOtest/testing/bentest 2.179s
30000 :总运行次数
50806 ns/op : 平均运行时间,即平均运行一次,要50806纳秒
另外还可以加 t.SetBytes(1111111)得到每次能向文件系统写入多mb数据
/* Benchmark 例子 Author:xcl Date:2015-11-22 */ package main import ( "fmt" "math/big" "testing" ) func BenchmarkXxxx(b *testing.B) { for i := 0; i < b.N; i++ { fmt.Sprintf("hello %d", i) } } func BenchmarkBigLen(b *testing.B) { big := NewBig() b.ResetTimer() for i := 0; i < b.N; i++ { big.BitLen() } } func NewBig() *big.Int { x := new(big.Int) x.MulRange(1, 10) return x } /* //测试结果: E:\GOtest\testing\bentest>go test b_test.go -bench=. -benchmem -cpu=1,2,4,8 testing: warning: no tests to run PASS BenchmarkXxxx 5000000 341 ns/op 32 B/op 2 allocs/op BenchmarkXxxx-2 5000000 323 ns/op 32 B/op 2 allocs/op BenchmarkXxxx-4 5000000 332 ns/op 32 B/op 2 allocs/op BenchmarkXxxx-8 5000000 330 ns/op 32 B/op 2 allocs/op BenchmarkBigLen 200000000 9.85 ns/op 0 B/op 0 allocs/op BenchmarkBigLen-2 200000000 9.86 ns/op 0 B/op 0 allocs/op BenchmarkBigLen-4 100000000 10.0 ns/op 0 B/op 0 allocs/op BenchmarkBigLen-8 200000000 9.82 ns/op 0 B/op 0 allocs/op ok command-line-arguments 18.085s */
样本测试:
Example_Xxx()
用来看运行中,输出的内容是否与预期的一样
func ExampleXxxx()
例子:
func ExampleHello() {
fmt.Println("hello")
// Output: hello
}
就是在下面,加一行 "// Output: 预期结果" 用来对比结果.
它的样本函数命令有些规则:
被测试对象是函数时:
func Example() { ... } //被测试对象是整个包
func ExampleF() { ... } //被测试对象是函数
func ExampleT() { ... } //被测试对象是类型
func ExampleT_M() { ... } //被测试对象是某个类型的一个函数
依前面规则取名后,还可以在后面加后缀以例区分
func Example_suffix() { ... }
func ExampleF_suffix() { ... }
func ExampleT_suffix() { ... }
func ExampleT_M_suffix() { ... }
二. 测试中的资源收集
在测试运行时,可以加上一些参数,用来采集监控资源使用情况。然后依Go提供的工具,作分析.
-cpuprofile cpu.out // 默认每10毫秒采样一次,cpu的使用情况
-memprofile mem.out //程序运行期间,堆内存的分配情况
-memprofilerate n //内存分配行为,默认每分配512k字节,采样一次
-blockprofile block.out //记录Goroutine阻塞事件
-blockprofilerate n // 控制记录Goroutine阻塞时候打点的纳秒数。默认不设置
// 就相当于-test.blockprofilerate=1,每一纳秒都打点记录一下
以cpuprofile为例:
E:\GOtest\testing\bentest>go test b_test.go -bench=. -benchmem -cpu=1,2,4,8 -cpuprofile cpu.out testing: warning: no tests to run PASS BenchmarkXxxx 5000000 351 ns/op 32 B/op 2 allocs/op BenchmarkXxxx-2 5000000 326 ns/op 32 B/op 2 allocs/op BenchmarkXxxx-4 5000000 326 ns/op 32 B/op 2 allocs/op BenchmarkXxxx-8 5000000 332 ns/op 32 B/op 2 allocs/op BenchmarkBigLen 200000000 9.91 ns/op 0 B/op 0 allocs/op BenchmarkBigLen-2 200000000 9.84 ns/op 0 B/op 0 allocs/op BenchmarkBigLen-4 100000000 10.2 ns/op 0 B/op 0 allocs/op BenchmarkBigLen-8 100000000 10.2 ns/op 0 B/op 0 allocs/op ok command-line-arguments 16.231s E:\GOtest\testing\bentest>dir 驱动器 E 中的卷是 doc 卷的序列号是 0E3D-2A1F E:\GOtest\testing\bentest 的目录 2015/11/22 11:59 <DIR> . 2015/11/22 11:59 <DIR> .. 2015/11/22 11:44 1,423 b_test.go 2015/11/22 11:59 63,024 cpu.out 2015/11/22 11:59 3,932,160 main.test.exe 3 个文件 3,996,607 字节 2 个目录 15,239,778,304 可用字节注意,生成了一个叫"main.test.exe"的可执行文件及cpu.out的输出文件。
可以利用它们来做分析
go tool pprof main.test.exe cpu.out
//查阅运行中,CPU使用情况 E:\GOtest\testing\bentest>go tool pprof main.test.exe cpu.out Entering interactive mode (type "help" for commands) (pprof) top10 12230ms of 16500ms total (74.12%) Dropped 62 nodes (cum <= 82.50ms) Showing top 10 nodes out of 55 (cum >= 1890ms) flat flat% sum% cum cum% 2910ms 17.64% 17.64% 4330ms 26.24% math/big.nat.bitLen 2850ms 17.27% 34.91% 7180ms 43.52% math/big.(*Int).BitLen 1420ms 8.61% 43.52% 1420ms 8.61% math/big.bitLen 1090ms 6.61% 50.12% 1250ms 7.58% runtime.mallocgc 1020ms 6.18% 56.30% 3510ms 21.27% fmt.(*pp).doPrintf 840ms 5.09% 61.39% 8020ms 48.61% command-line-arguments.BenchmarkBigLen 820ms 4.97% 66.36% 1090ms 6.61% fmt.(*fmt).integer 550ms 3.33% 69.70% 550ms 3.33% runtime.memmove 400ms 2.42% 72.12% 400ms 2.42% runtime.mSpan_Sweep.func1 330ms 2.00% 74.12% 1890ms 11.45% fmt.(*pp).printArg (pprof) (pprof) help Commands: cmd [n] [--cum] [focus_regex]* [-ignore_regex]* Produce a text report with the top n entries. Include samples matching focus_regex, and exclude ignore_regex. Add --cum to sort using cumulative data. Available commands: callgrind Outputs a graph in callgrind format disasm Output annotated assembly for functions matching regexp or address dot Outputs a graph in DOT format eog Visualize graph through eog evince Visualize graph through evince gif Outputs a graph image in GIF format gv Visualize graph through gv list Output annotated source for functions matching regexp pdf Outputs a graph in PDF format peek Output callers/callees of functions matching regexp png Outputs a graph image in PNG format proto Outputs the profile in compressed protobuf format ps Outputs a graph in PS format raw Outputs a text representation of the raw profile svg Outputs a graph in SVG format tags Outputs all tags in the profile text Outputs top entries in text form top Outputs top entries in text form tree Outputs a text rendering of call graph web Visualize graph through web browser weblist Output annotated source in HTML for functions matching regexp or address peek func_regex Display callers and callees of functions matching func_regex. ......... (pprof) weblist (pprof) web Cannot find dot, have you installed Graphviz?下载安装个 Graphviz ,就能出图了.
用于测试的Main函数:
TestMain(m *testing.M)
来个例子:
/* TestMain例子 Author:xcl Date: 2015-11-22 */ package main import ( "flag" "log" "os" "testing" ) var wordPtr = flag.String("word", "foo", "a string") func TestMain(m *testing.M) { flag.Parse() log.Println("[TestMain] word:", *wordPtr) log.Println("[TestMain] run()前") exitVal := m.Run() log.Println("[TestMain] run()后") os.Exit(exitVal) } func Test1(t *testing.T) { log.Println("[Test1] running ", *wordPtr) } /* E:\GOtest\testing\t2>go test t2_test.go -v -trace trace.out -word xcl...... 2015/11/22 18:11:43 [TestMain] word: xcl...... 2015/11/22 18:11:43 [TestMain] run()前 === RUN Test1 2015/11/22 18:11:43 [Test1] running xcl...... --- PASS: Test1 (0.00s) PASS 2015/11/22 18:11:43 [TestMain] run()后 ok command-line-arguments 0.101s E:\GOtest\testing\t2>dir 驱动器 E 中的卷是 doc 卷的序列号是 0E3D-2A1F E:\GOtest\testing\t2 的目录 2015/11/22 18:11 <DIR> . 2015/11/22 18:11 <DIR> .. 2015/11/22 18:11 3,666,944 main.test.exe 2015/11/22 18:11 2,234 t2_test.go 2015/11/22 18:11 730 trace.out 3 个文件 3,669,908 字节 2 个目录 15,177,601,024 可用字节 E:\GOtest\testing\t2>go tool trace main.test.exe trace.out */
三.测试覆盖率:
覆盖率是指被测试对象有多少代码在刚刚的测试中被用到。
go test -cover prj/pkg
go test prj/pkg -coverpkg=pkg1,pkg2
go test prj/pkg -coverpkg=pkg1,pkg2 -coverprofile=cover.out
go tool cover -html=cover.out
-func=cover.out //输出每个函数的测试覆盖率概要信息
-html=cover.out //将概要文件内容转成html并浏览
-mode=cover.out //设计概要文件编译模式
-o=cover.out //...
-var=GoCover // ...
参考资料: https://golang.org/pkg/testing/
https://golang.org/cmd/go/#hdr-Description_of_testing_flags
https://github.com/polaris1119/The-Golang-Standard-Library-by-Example/blob/master/chapter09/09.1.md
郝林的<<Go语言并发编程实战>>测试篇
其实细节,具体查相关资料。 另外,Go源码包下也有很多详细的例子.
先整理到这,HTTP/WebSocket之类怎么测试及性能优化方面的再另写.
BLOG: http://blog.csdn.ent/xcl168
有疑问加站长微信联系(非本文作者)