Golang 語言怎麼編寫測試代碼?

**01 **

介紹

我們使用 Golang 語言開發的項目,怎麼保證邏輯正確和性能要求呢?也就是說我們如何測試我們的 Golang 代碼呢?在 Golang 語言中,可以使用標準庫 testing 包編寫單元測試和基準測試,使用 go test 命令執行單元測試和基準測試的代碼。本文我們介紹在 Golang 語言中怎麼編寫測試代碼。

**02 **

命名規範

在 Golang 語言中編寫測試代碼,需要遵循一些命名規範,包含文件名、包名、函數(方法)名和變量名。

文件名和包名

測試文件名以 _test.go 結尾,go test 工具可以遍歷以 _test.go 結尾的文件,執行測試函數。而 go buildgo run 會忽略以 _test.go 結尾的文件,文件名開頭一般是被測試函數所在的文件名。

包名一般和被測試文件的包名相同,這樣即可以測試被測試文件的可導出函數和不可導出函數。

函數名和方法名

測試函數(方法)名必須以 Test、Benchmark 和 Example 開頭,並且必須是可導出函數。函數名一般是被測試函數名,首字母大寫。如果我們需要給同一個函數編寫多個測試函數,可以在函數名後接上測試函數的場景,例如:TestXxxxXxxx

變量名

測試函數(方法)的變量名,Golang 語言和 go test 工具沒有明確的約束,但是,社區針對輸出結果有一些規範供大家參考。在編寫單元測試代碼時,一般會得到一個實際輸出結果,和一個我們預期的輸出結果做對比。針對這兩個變量,社區的變量名規範是 got/wantexpected/actual

**03 **

編寫測試代碼

單元測試

所謂單元測試,顧名思義就是對單元進行測試,一般進行測試的單元是一個最小的單元,在 Golang 語言中,最小的單元就是指一個函數或方法。

單元測試的函數,函數名以 Test 開頭,例如:TestXxx。參數必須是 *testing.T 類型,可以使用該類型的方法記錄測試信息和測試狀態。例如,一般使用 LogLogf 記錄測試信息,使用 ErrorErrorfFatalFatalf 方法記錄測試狀態,該類型的更多方法可以閱讀官方文檔。

被測試函數:

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 **

總結

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

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

參考資料:

https://pkg.go.dev/testing

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/P4elvWrbA8qcDcGLBcy-0Q