1. 程式人生 > 實用技巧 >Go的單元測試

Go的單元測試

單元測試的作用

單元測試一般用來測試自己寫的程式碼邏輯是否有問題,能不能按照自己的預期執行,便於自己在上線之前檢驗程式碼質量。

在我自己使用單元測試的過程中,我自己一般都是針對某個函式進行測試,判斷這個函式是否能夠達到預期效果。為了在Go中使用單元測試,我們需要在xxx_test.go檔案中匯入testing包,通過go test命令實現自動執行如下形式的函式:

func TestFuncName(*testing.T)

需要注意的是:FuncName的函式名第一個字母不能小寫

在上面的測試函式中,如果需要傳送失敗訊息我們可以使用Error或者FailFatal這些方法,執行成功的話我們也可以使用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測試的示例,我在原來的檔案中分別實現一個AddTest_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的通用方法

  1. 碰到斷言錯誤,會判斷這個測試用例失敗,可能會使用到

Fail : case失敗,繼續後面的測試用例
FaileNow: case失敗,終止測試

  1. 碰到斷言錯誤時希望跳過這個錯誤,但是不希望標識case失敗,使用

SkipNow : case跳過,終止測試

  1. 只希望在一個地方列印資訊,使用

Log: 輸出資訊
Logf: 輸出格式化的資訊

  1. 希望跳過這個case並且列印資訊

Skip: = Log + SkipNow
Skipf: = Logf + SkipNow

  1. case失敗的時候打印出資訊,並且中斷測試用例

Fatal: = Log + FailNow
Fatalf: = Logf + FailNow

  1. case失敗的時候打印出資訊,並且希望測試繼續

Error: = Log + Fail
Errorf: = Logf + Fail

參考文件