1. 程式人生 > 其它 >golang之測試testing

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 記錄測試資訊,使用 ErrorErrorfFatal 和 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 

總結

本文我們介紹怎麼編寫測試程式碼,包含單元測試和基準測試。特別需要注意的是一些命名規範。

養成編寫測試程式碼的習慣,不僅可以降低程式碼邏輯的錯誤率,而且在多人開發中,還可以提升聯調效率和提測通過率。