13.7 Go 中的單元測試和基準測試
首先所有的包都應該有一定的必要文檔,然後同樣重要的是對包的測試。
在第 3 章中提到了 Go 的測試工具 gotest, 我們已經在 9.8 節中使用過了。這裏我們會用更多的例子進行詳細說明。
名爲 testing 的包被專門用來進行自動化測試,日誌和錯誤報告。並且還包含一些基準測試函數的功能。
備註:gotest 是 Unix bash 腳本,所以在 Windows 下你需要配置 MINGW 環境(參見 2.5 節);在 Windows 環境下把所有的 pkg/linux_amd64 替換成 pkg/windows。
對一個包做(單元)測試,需要寫一些可以頻繁(每次更新後)執行的小塊測試單元來檢查代碼的正確性。於是我們必須寫一些 Go 源文件來測試代碼。測試程序必須屬於被測試的包,並且文件名滿足這種形式 *_test.go
,所以測試代碼和包中的業務代碼是分開的。
_test
程序不會被普通的 Go 編譯器編譯,所以當放應用部署到生產環境時它們不會被部署;只有 gotest 會編譯所有的程序:普通程序和測試程序。
測試文件中必須導入 "testing" 包,並寫一些名字以 TestZzz
打頭的全局函數,這裏的 Zzz
是被測試函數的字母描述,如 TestFmtInterface,TestPayEmployees 等。
測試函數必須有這種形式的頭部:
func TestAbcde(t *testing.T)
T 是傳給測試函數的結構類型,用來管理測試狀態,支持格式化測試日誌,如 t.Log,t.Error,t.ErrorF 等。在函數的結尾把輸出跟想要的結果對比,如果不等就打印一個錯誤。成功的測試則直接返回。
用下面這些函數來通知測試失敗:
1)func (t *T) Fail()
標記測試函數爲失敗,然後繼續執行(剩下的測試)。
2)func (t *T) FailNow()
標記測試函數爲失敗並中止執行;文件中別的測試也被略過,繼續執行下一個文件。
3)func (t *T) Log(args ...interface{})
args 被用默認的格式格式化並打印到錯誤日誌中。
4)func (t *T) Fatal(args ...interface{})
結合 先執行 3),然後執行 2)的效果。
運行 go test 來編譯測試程序,並執行程序中所有的 TestZZZ 函數。如果所有的測試都通過會打印出 PASS。
gotest 可以接收一個或多個函數程序作爲參數,並指定一些選項。
結合 --chatty 或 -v 選項,每個執行的測試函數以及測試狀態會被打印。
例如:
go test fmt_test.go --chatty
=== RUN fmt.TestFlagParser
--- PASS: fmt.TestFlagParser
=== RUN fmt.TestArrayPrinter
--- PASS: fmt.TestArrayPrinter
...
testing 包中有一些類型和函數可以用來做簡單的基準測試;測試代碼中必須包含以 BenchmarkZzz
打頭的函數並接收一個 *testing.B
類型的參數,比如:
func BenchmarkReverse(b *testing.B) {
...
}
命令 go test –test.bench=.*
會運行所有的基準測試函數;代碼中的函數會被調用 N 次(N是非常大的數,如 N = 1000000),並展示 N 的值和函數執行的平均時間,單位爲 ns(納秒,ns/op)。如果是用 testing.Benchmark 調用這些函數,直接運行程序即可。
具體可以參見 14.16 節中用 goroutines 運行基準測試的例子以及練習 13.4:string_reverse_test.go