Go的單元測試
單元測試的作用
單元測試一般用來測試自己寫的程式碼邏輯是否有問題,能不能按照自己的預期執行,便於自己在上線之前檢驗程式碼質量。
在我自己使用單元測試的過程中,我自己一般都是針對某個函式進行測試,判斷這個函式是否能夠達到預期效果。為了在Go中使用單元測試,我們需要在xxx_test.go
檔案中匯入testing
包,通過go test
命令實現自動執行如下形式的函式:
func TestFuncName(*testing.T)
需要注意的是:
FuncName
的函式名第一個字母不能小寫
在上面的測試函式中,如果需要傳送失敗訊息我們可以使用Error
或者Fail
和Fatal
這些方法,執行成功的話我們也可以使用Log
在編寫單元測試的時候,我們需要建立一個以_test.go
結尾的檔案,檔案中包含了Test_FuncName
函式。並且這兩個檔案放在同一個package下。通過執行go test xxx.go
來進行單元測試。
單元測試示例
在這我將會在strings.go中寫個方法Contains
,然後在strings_test.go檔案中寫一個測試函式TestContains
,並且我將這兩個檔案放在同一個package下,具體如下所示:
strings.go
func Contains(s, substr string) bool { return strings.Contains(s, substr) }
strings_test.go
func TestContains(t *testing.T) {
res := basic.Contains("res", "e")
if res == true {
t.Log("the result is OK")
} else {
t.Fatal("the result is wrong")
}
}
然後開啟cmd視窗,輸入命令go test -v .\strings_test.go,可以看到輸出結果如下:
=== RUN TestContains TestContains: strings_test.go:12: the result is OK --- PASS: TestContains (0.00s) PASS ok command-line-arguments (cached)
Table-Driven Test(TDT)
上面的測試中只輸入了一個case,並沒有實現case覆蓋,測試結果可能會不全。所以如果在一個測試中需要測試多個case,如果我們直接在程式碼中輸入多個case,這將會很費時費力。但是不需要擔心,我們可以使用table-driven的方式來實現測試函式。為了實現多個case測試的示例,我在原來的檔案中分別實現一個Add和Test_Add函式,示例如下:
strings.go
func Add(a, b int) int {
return a + b
}
strings_test.go
func TestAdd(t *testing.T) {
// define table
var addtests = []struct {
a int
b int
res int // expected result
}{
{1,1,2},
{2,3,5},
{3,4,7},
{5,6,11},
{6,5,11},
{1,22,23},
}
for _, sum := range addtests {
actual := basic.Add(sum.a, sum.b)
if actual != sum.res {
t.Errorf("Add(%d + %d ) = %d, expected result is %d", sum.a, sum.b, actual ,sum.res)
}
}
}
輸入命令go test -v .\strings_test.go得到如下結果
=== RUN TestAdd
--- PASS: TestAdd (0.00s)
PASS
ok command-line-arguments 0.222s
testing的結構體
- B : 壓力測試
- BenchmarkResult : 壓力測試結果
- Cover : 程式碼覆蓋率相關結構體
- CoverBlock : 程式碼覆蓋率相關結構體
- InternalBenchmark : 內部使用的結構體
- InternalExample : 內部使用的結構體
- InternalTest : 內部使用的結構體
- M : main 測試使用的結構體
- PB : Parallel benchmarks 並行測試使用的結構體
- T : 普通測試用例
- TB : 測試用例的介面
testing的通用方法
- 碰到斷言錯誤,會判斷這個測試用例失敗,可能會使用到
Fail : case失敗,繼續後面的測試用例
FaileNow: case失敗,終止測試
- 碰到斷言錯誤時希望跳過這個錯誤,但是不希望標識case失敗,使用
SkipNow : case跳過,終止測試
- 只希望在一個地方列印資訊,使用
Log: 輸出資訊
Logf: 輸出格式化的資訊
- 希望跳過這個case並且列印資訊
Skip: = Log + SkipNow
Skipf: = Logf + SkipNow
- case失敗的時候打印出資訊,並且中斷測試用例
Fatal: = Log + FailNow
Fatalf: = Logf + FailNow
- case失敗的時候打印出資訊,並且希望測試繼續
Error: = Log + Fail
Errorf: = Logf + Fail