这书是之前 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