前言
Go語言本身集成了輕量級的測試框架,由go test命令和testing包組成。包含單元測試和壓力測試,是保證我們編寫健壯Golang程序的有效工具。
演示環境
$ uname -a Darwin 18.6.0 Darwin Kernel Version 18.6.0: Thu Apr 25 23:16:27 PDT 2019; root:xnu-4903.261.4~2/RELEASE_X86_64 x86_64 $ go version go version go1.12.4 darwin/amd64
示例
老規矩,我會用一個簡單的示例演示go test的用法,讓大家有一個直觀的感受。
$ ls my.go my_test.go $ go test -v === RUN TestAbs --- PASS: TestAbs (0.00s) PASS ok mytest 0.006s
my.go文件內容:
package mytest func Abs(a int) int { if a < 0 { return -1*a } return a }
my_test.go文件的內容:
package mytest import "testing" func TestAbs(t *testing.T) { result := Abs(-1) if result != 1 { t.Errorf("Abs(-1) = %d; want 1", result) } }
可以看出,測試文件是以_test.go結尾的文件,包含函數名TestXXX的文件簽名func (t *testing.T)。測試框架會按函數定義的順序依次執行Test開頭的函數。如果測試函數調用錯誤函數,比如t.Error,t.Fail,那么測試就會認為是失敗的。但是不會強制退出,測試程序還是會接着往下運行,除非調用t.Fatal,就會打印錯誤信息,並且強制退出。go test會自動編譯運行_test.go結尾的文件,go build不會編譯_test.go結尾的文件,所以不用擔心test文件和正式文件定義為同一個包導致包大小增大。
詳細用法
go test執行時會編譯_test結尾的文件,執行文件中以Test,Benchmark,Example 開頭的測試函數。建議_test.go文件和源文件聲明為同一個包。單元測試函數TestXXX的參數是testing.T,BenchmarkXXX的參數是testing.B,函數內以b.N作為循環次數,其中N會動態變化。可以通過testing.T的Error,Errorf,Fail,Fatal,Fatalf 來說明測試不通過。
表格驅動測試
上述的示例單元測試用了-1這個測試用例來演示測試用法,但是在實際生產中我們編寫一個測試函數肯定會有多種測試用例,各種邊界條件,那這種情況應該怎么辦呢?難道要每個測試用例拷貝一份上述的測試函數嗎,顯然是不合適的。這就介紹接下來的表格驅動測試(table driven test):
package mytest import "testing" func TestAbs(t *testing.T) { var testcases = []struct { in int out int }{ {-1, 1}, {0, 0}, {2, 2}, {123, 123}, {-30, -30}, } for _, tc := range testcases { result := Abs(tc.in) if result != tc.out { t.Fatalf("Abs(%d) = %d; want %d", tc.in, result, tc.out) } } }
表格的每一項是一個完整的測試用例,包含輸入信息和期望的輸出結果,有時候還包含測試用例名稱等額外信息。這樣我們就可以在表格里面編寫各種測試用例場景,包括常規場景,邊界場景,和一些異常場景。運行結果為:
$ go test -v === RUN TestAbs --- FAIL: TestAbs (0.00s) my_test.go:19: Abs(-30) = 30; want -30 FAIL exit status 1 FAIL mytest 0.005s
性能測試
性能測試函數以是Benchmark開頭,格式為:
func Benchmark(b *testing.B)
go test 默認是不會運行_test.go文件中的Benchmark函數,需要通過-bench選項開啟。演示代碼:
package mytest import "testing" func BenchmarkAbs(b *testing.B) { for i := 0; i < b.N; i++ { result := Abs(i) if result != i { b.Errorf("benchmark faild, abs(%d) result %d, except %d", i, result, i) } } }
運行結果:
$ go test -bench=".*" goos: darwin goarch: amd64 pkg: mytest BenchmarkAbs-12 2000000000 0.26 ns/op PASS ok mytest 0.553s
-bench后面跟的是正則表達式,我們可以指定需要匹配運行的benchmark函數,示例中的.*表示運行所有的benchmark函數。
上述結果顯示總共運行了0.553s,一共運行了2000000000次,平均每次運行的時間是0.26納秒。
總結
文章介紹了Go語言自帶的go test測試框架的單元測試和性能測試方法。下篇將會講解gomock模擬實際的生產接口。
參考
https://golang.org/pkg/testing/
https://github.com/golang/go/wiki/TableDrivenTests
https://golang.org/doc/code.html#Testing