Golang相關測試框架
在 Go 語言裏,最常用的測試框架有:自帶的 testing 包、GoConvey 和 testify。
1、Go自帶的testing包
testing 包是官方內置的,無需額外安裝,也是大多數項目的首選。
(1)單元測試
-
測試文件必須以
_test.go結尾,例如:calc_test.go -
測試函數必須以
Test開頭(推薦寫成Test+函數名,更直觀) -
測試函數簽名固定:
func TestXxx(t *testing.T),不能有返回值 -
測試函數內部用
t.Errorf/t.Fatal等方法輸出錯誤- t.Errorf:標記測試失敗,但 繼續執行後面的測試代碼。
- t.Fatal:標記測試失敗,並 立即中止當前測試函數。
# 執行當前目錄下所有 *_test.go 文件 go test -v # 只執行指定文件中的測試 go test -v calc_test.go calc.go # 執行指定的測試函數(-count=1 表示禁用緩存,強制重新運行) go test -v -run TestAdd calc_test.go calc.go -count=1
(2)性能測試
-
文件命名:和單測一樣,文件必須以
_test.go結尾,這樣go test才能識別。 -
函數命名:基準測試函數要以
Benchmark開頭,且必須是導出函數,比如BenchmarkAdd。 -
函數簽名:基準測試函數必須接收一個
*testing.B類型的參數,不能有返回值。 -
重置計時器:
b.ResetTimer()用來清空前面初始化代碼的耗時,保證只統計真正的測試部分。 -
循環執行:基準測試裏要用
for i := 0; i < b.N; i++ { ... },被測的代碼放在循環裏。 -
b.N 的作用:Go 框架會自動調整
b.N,讓測試至少運行 1 秒左右,這樣結果更穩定。最終輸出的是平均每次運行的耗時(比如0.25 ns/op表示每次 0.25 納秒)。
在calc文件夾的calc_test.go文件中新增BenchmarkAbs和BenchmarkAdd方法。

基準測試的目標就是 儘可能準確地衡量一段代碼的性能,包括運行時間、內存分配等。
-
核心思路:同一段代碼運行很多次(
b.N次),用「總耗時 ÷ b.N」算出平均每次執行的耗時。 -
b.N 的作用:
b.N由 Go 測試框架自動決定,會動態調整,保證測試至少運行 1 秒左右,避免樣本太少導致結果不準。 -
運行過程:當執行
go test -bench=.時,框架會先用很小的b.N(比如 1、2、5、19)試跑幾次,估算耗時,再逐步增大b.N,直到結果穩定。 -
輸出示例:比如報告裏寫
1000000000 0.25 ns/op,意思是運行了 10 億次,每次平均耗時 0.25 納秒。


# 運行所有基準測試 go test -bench=. # 運行所有基準測試並顯示內存分配情況 go test -bench=. -benchmem # 只運行基準測試,不運行單元測試 go test -run=none -bench=. # 指定測試時間 go test -bench=. -benchtime=3s # 指定運行輪數 go test -bench=. -count=3 # 組合使用多種參數 go test -run=none -bench=. -benchmem -benchtime=3s -count=3
2、GoConvey
go test 命令就能照常運行;如果你想要更直觀的體驗,可以直接運行 goconvey,然後在瀏覽器裏訪問 http://localhost:8080,就能看到實時的測試結果展示。
相比起純粹使用標準庫的 testing 包,Convey 讓單元測試的書寫和閲讀都更流暢,尤其適合需要頻繁跑測試、調試邏輯的開發過程。
(1)安裝依賴:go get github.com/smartystreets/goconvey
(2)demo


3、testify
Testify 是 Go 語言生態裏非常常用的一個 斷言風格測試框架。它不僅提供了開發者最常用的斷言方法(讓測試代碼更簡潔、可讀性更強),還額外封裝了三個核心功能模塊:
-
Assertions(斷言):內置了豐富的斷言方法,避免重複編寫樣板式判斷邏輯。
-
Suite(測試套件):支持將一組相關測試組織在一起,方便共享初始化、清理等邏輯。
-
Mock(模擬):提供強大的 Mock 能力,方便在單元測試中模擬依賴對象或外部接口。
藉助 Testify,我們可以用更接近自然語言的方式編寫測試,不僅提高開發效率,也讓測試結果更易於理解。
(1)依賴安裝:go get -u -v github.com/stretchr/testify
(2)測試用例
① assert包提供了斷言工具,在執行時會將case標記為失敗,但程序不會退出,而是繼續往下執行。
package testify import ( "testing" "github.com/stretchr/testify/assert" ) func Test_assert(t *testing.T) { a := 2 b := 3 // 第一個斷言失敗(故意寫錯期望值) assert.Equal(t, 6, a+b, "第一個斷言:2+3應該等於5,不是6") // 程序繼續執行下面的斷言 t.Log("這行代碼被執行了,説明程序沒有中斷") // 第二個斷言通過 assert.Equal(t, 5, a+b, "第二個斷言:2+3應該等於5") // 第三個斷言也會執行 assert.True(t, a < b, "第三個斷言:2應該小於3") t.Log("所有斷言都已執行完畢") }

② require包提供與asser包相同的全局函數,與assert不同的是,require會終止當前測試。
package testify import ( "testing" "github.com/stretchr/testify/require" ) func Test_require(t *testing.T) { name := "Tom" age := 18 // 這個會失敗並停止測試 require.Equal(t, "dazuo", name, "測試會在這裏停止") require.Equal(t, 18, age, "測試會在這裏停止") // 這行不會被執行 t.Log("這行代碼不會被執行") }

③ mock包提供了一種輕鬆編寫模擬對象的機制,可以在編寫測試代碼時替代實際對象使用模擬對象。
func Test_mock(t *testing.T) { // 創建模擬對象 mockS := &mockStorage{} // 設置對Store方法期望的調用,參數必須匹配;返回該方法調用時的返回值 mockS.On("Store", "name", "Tom").Return(1, nil).Once() result, err := mockS.Store("name", "Tom") assert.NoError(t, err) assert.Equal(t, 1, result) mockS.AssertExpectations(t) // 斷言所有預期的調用都發生了 }

若該方法沒有被調用:
func Test_mock(t *testing.T) { // 創建模擬對象 mockS := &mockStorage{} // 設置對Store方法期望的調用,參數必須匹配;返回該方法調用時的返回值 mockS.On("Store", "name", "Tom").Return(1, nil).Once() mockS.AssertExpectations(t) // 斷言所有預期的調用都發生了 }
