最近一直在搞各種測試,然後今天周末翻翻書,發現特價蘿蔔的書上在測試方面寫得挺全的。
這書是之前 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 := *benchTimefor !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 mainimport ("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:xclDate:2015-11-22*/package mainimport ("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,8testing: warning: no tests to runPASSBenchmarkXxxx 5000000 341 ns/op 32 B/op 2 allocs/opBenchmarkXxxx-2 5000000 323 ns/op 32 B/op 2 allocs/opBenchmarkXxxx-4 5000000 332 ns/op 32 B/op 2 allocs/opBenchmarkXxxx-8 5000000 330 ns/op 32 B/op 2 allocs/opBenchmarkBigLen 200000000 9.85 ns/op 0 B/op 0 allocs/opBenchmarkBigLen-2 200000000 9.86 ns/op 0 B/op 0 allocs/opBenchmarkBigLen-4 100000000 10.0 ns/op 0 B/op 0 allocs/opBenchmarkBigLen-8 200000000 9.82 ns/op 0 B/op 0 allocs/opok 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.outtesting: warning: no tests to runPASSBenchmarkXxxx 5000000 351 ns/op 32 B/op 2 allocs/opBenchmarkXxxx-2 5000000 326 ns/op 32 B/op 2 allocs/opBenchmarkXxxx-4 5000000 326 ns/op 32 B/op 2 allocs/opBenchmarkXxxx-8 5000000 332 ns/op 32 B/op 2 allocs/opBenchmarkBigLen 200000000 9.91 ns/op 0 B/op 0 allocs/opBenchmarkBigLen-2 200000000 9.84 ns/op 0 B/op 0 allocs/opBenchmarkBigLen-4 100000000 10.2 ns/op 0 B/op 0 allocs/opBenchmarkBigLen-8 100000000 10.2 ns/op 0 B/op 0 allocs/opok command-line-arguments 16.231sE:\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.go2015/11/22 11:59 63,024 cpu.out2015/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.outEntering interactive mode (type "help" for commands)(pprof) top1012230ms 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) webCannot find dot, have you installed Graphviz?
下載安裝個 Graphviz ,就能出圖了.
用於測試的Main函數:
TestMain(m *testing.M)
來個例子:
/*TestMain例子Author:xclDate: 2015-11-22*/package mainimport ("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 Test12015/11/22 18:11:43 [Test1] running xcl......--- PASS: Test1 (0.00s)PASS2015/11/22 18:11:43 [TestMain] run()後ok command-line-arguments 0.101sE:\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.exe2015/11/22 18:11 2,234 t2_test.go2015/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