golang之測試testing
01
介紹
我們使用 Golang 語言開發的專案,怎麼保證邏輯正確和效能要求呢?也就是說我們如何測試我們的 Golang 程式碼呢?在 Golang 語言中,可以使用標準庫 testing 包編寫單元測試和基準測試,使用 go test
命令執行單元測試和基準測試的程式碼。本文我們介紹在 Golang 語言中怎麼編寫測試程式碼。
02
命名規範
在 Golang 語言中編寫測試程式碼,需要遵循一些命名規範,包含檔名、包名、函式(方法)名和變數名。
檔名和包名
測試檔名以 _test.go
結尾,go test
工具可以遍歷以 _test.go
結尾的檔案,執行測試函式。而 go build
和 go run
_test.go
結尾的檔案,檔名開頭一般是被測試函式所在的檔名。
包名一般和被測試檔案的包名相同,這樣即可以測試被測試檔案的可匯出函式和不可匯出函式。
函式名和方法名
測試函式(方法)名必須以 Test、Benchmark 和 Example 開頭,並且必須是可匯出函式。函式名一般是被測試函式名,首字母大寫。如果我們需要給同一個函式編寫多個測試函式,可以在函式名後接上測試函式的場景,例如:TestXxxxXxxx
。
變數名
測試函式(方法)的變數名,Golang 語言和 go test
工具沒有明確的約束,但是,社群針對輸出結果有一些規範供大家參考。在編寫單元測試程式碼時,一般會得到一個實際輸出結果,和一個我們預期的輸出結果做對比。針對這兩個變數,社群的變數名規範是 got/want
expected/actual
。
03
編寫測試程式碼
單元測試
所謂單元測試,顧名思義就是對單元進行測試,一般進行測試的單元是一個最小的單元,在 Golang 語言中,最小的單元就是指一個函式或方法。
單元測試的函式,函式名以 Test
開頭,例如:TestXxx
。引數必須是 *testing.T
型別,可以使用該型別的方法記錄測試資訊和測試狀態。例如,一般使用 Log
和 Logf
記錄測試資訊,使用 Error
、Errorf
、Fatal
和 Fatalf
方法記錄測試狀態,該型別的更多方法可以閱讀官方文件。
被測試函式:
func Sum(a, b int) int {
return a+b
}
測試函式:
func TestSum(t *testing.T) {
a, b := 1,2
rst := Sum(a, b)
if rst == 3 {
t.Logf("expected=%d, actual=%d", 3, rst)
} else {
// t.Errorf("expected=%d, actual=%d", 3, rst)
t.Fatalf("expected=%d, actual=%d", 3, rst)
}
t.Log("done")
}
閱讀上面這段程式碼,是我們編寫的 Sum 函式的單元測試,給定 a, b 兩個變數作為 Sum 函式的輸入引數,此外,我們還可以使用表格測試發,給定一組被測試函式的輸入引數,限於篇幅,本文不準備花費篇幅介紹。
使用 go test
命令執行以上單元測試的程式碼:
go test
PASS
ok learn_go/lesson27 0.555s
go test
命令遍歷所有 _test.go
結尾的檔案,執行檔案中所有的測試函式。此外,go test
支援一些引數,例如,-v
輸出測試函式的執行詳情;-run
指定執行的測試函式;-count
指定執行次數。
此外,使用引數 --coverprofile
統計單元測試的覆蓋率。
go test --coverprofile=func.cover
PASS
coverage: 100.0% of statements
ok learn_go/lesson27 0.499s
閱讀上面的執行結果,可以發現我們編寫的單元測試覆蓋率為 100%。
如果我們想要檢視詳細的覆蓋率統計結果,我們可以執行以下命令生成 html
檔案,使用瀏覽器開啟生成的 html
檔案,可以檢視詳細的單元測試覆蓋率統計結果。
go tool cover -html=func.cover -o func_cover.html
執行以上命令,會生成一個名為 func_cover.html
的檔案,我們可以使用瀏覽器開啟它,檢視詳細的單元測試覆蓋率統計結果。
基準測試
在 Golang 語言中,可以使用基準測試檢視程式碼的效能。基準測試的函式名以 Benchmark
開頭,例如:BenchmarkXxx
。引數必須是 *testing.B
型別,函式體中 for 迴圈的條件,以 b.N
作為迴圈次數,它是基準測試框架提供的,它在 Golang 執行時動態調整,通過多次測試,得到效能評估結果。
示例程式碼:
func BenchmarkSum(b *testing.B) {
for i := 0; i < b.N; i++ {
Sum(1, 2)
}
}
我們可以使用 go test
工具執行以上基準測試的程式碼,基準測試函式不會自動執行,必須使用引數 -bench
。
go test -bench=".*"
goos: darwin
goarch: amd64
pkg: learn_go/lesson27
cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
BenchmarkSum-16 1000000000 0.2325 ns/op
PASS
ok learn_go/lesson27 0.748s
閱讀上面的執行結果,我們主要介紹一下 BenchmarkXxx-n
這一行的意思。這一行共有三列,第一列 BenchmarkSum-16
分別代表基準測試的函式名和參與基準測試的 CPU 執行緒數,預設是 GOMAXPROCS 的值。第二列 1000000000
表示基準測試迴圈執行的次數。第三列 0.2325 ns/op
表示每次迴圈的平均執行耗時是 0.2325
納秒,該值越小,說明程式碼效能越高。
除了 b.N
之外,還有幾個關於效能測試時間計數的方法,例如:b.ResetTimer()
、b.StopTimer()
和 b.StartTimer()
,我們可以根據我們的測試場景,靈活使用。
此外,go test
工具關於基準測試的引數,除了引數 -bench
之外,還有 -benchmem
統計記憶體分配;-cpu
指定參與執行基準測試的 CPU 執行緒數;-benchtime
指定測試時間和迴圈次數,其中值的單位為 s
表示指定執行多少秒,單位為 x
表示指定迴圈執行次數;-timeout
指定基準測試函式執行的超時時間。
04
總結
本文我們介紹怎麼編寫測試程式碼,包含單元測試和基準測試。特別需要注意的是一些命名規範。
養成編寫測試程式碼的習慣,不僅可以降低程式碼邏輯的錯誤率,而且在多人開發中,還可以提升聯調效率和提測通過率。