1. 程式人生 > 資訊 >因微軟收購一事,動視暴雪被紐約市起訴

因微軟收購一事,動視暴雪被紐約市起訴

go test 命令

go test命令是一個按照一定的約定和組織來測試程式碼的程式。在包目錄內,所有以_test.go為字尾名的原始檔在執行go build時不會被構建成包的一部分,它們是go test測試的一部分。

*_test.go檔案中,有三種類型的函式:測試函式基準測試(benchmark)函式、示例函式

  • 測試函式是以Test為函式名字首的函式,用於測試程式的一些邏輯行為是否正確;go test命令會呼叫這些測試函式並報告測試結果是PASS或FAIL。
  • 基準測試函式是以Benchmark為函式名字首的函式,它們用於衡量一些函式的效能;go test命令會多次執行基準測試函式以計算一個平均的執行時間。
  • 示例函式是以Example為函式名字首的函式,提供一個由編譯器保證正確性的示例文件。

go test 可以使用額外引數列印更多的資訊,不過大部分IDE集成了這部分功能

引數名 功能
-v 列印每個測試函式的名字和執行時間
-run -run = xxx對應一個正則表示式,只有測試函式名被它正確匹配的測試函式才會被go test測試命令執行
-cover 獲得測試的程式碼覆蓋率摘要
-bench -bench = xxx 指定要執行的基準測試函式

測試函式

  • 每個測試函式必須匯入testing包。
  • 測試函式名必須以 Test 開頭
  • *testing.T 型別引數用於報告測試失敗和附加的日誌資訊
func TestName(t *testing.T) {
    // ...
}

為了方便新增測試資料,我們可以將測試資料合併到一個表格之中,比如一個結構體陣列中,這種測試方式稱之為表格驅動的測試

func TestBruteForce(t *testing.T) {
	var tests = []struct {
		s       string  // 主串
		pattern string  // 模式串
		want    int     // 主串中匹配到的模式串的起始下標
	}{
		{"abcd", "bcd", 1},
		{"abcd", "e", -1},
		{"abcd", "", 0},
	}

	for _, test := range tests {
		if got := bruteForce(test.s, test.pattern); got != test.want {
			t.Errorf("bruteForce(%q, %q) = %v", test.s, test.pattern, got)
		}
	}
}

上面這段程式碼,測試一個字串匹配函式。如果有新的測試樣例,就可以直接加到表格的下一行中,非常方便。

除了構造精心設計的測試樣例,有時候我們想通過構造更廣泛的隨即輸入來測試函式的行為,這種測試思路為隨機測試

func TestRandomBruteForce(t *testing.T) {
	seed := time.Now().UTC().UnixNano()
	rng := rand.New(rand.NewSource(seed))
	t.Logf("Random seed: %d", seed) //在日誌中記錄隨機數種子
	for i := 0; i < 1000; i++ {
		s, pattern, start := randomString(rng)
		if got := bruteForce(s, pattern); got != start {
			t.Errorf("bruteForce(%q, %q) = %v", s, pattern, got)
		}

	}
}

// 隨機生成主串和子串
func randomString(rng *rand.Rand) (string, string, int) {
	n := rng.Intn(25) // 隨機字串長度
	bytes := make([]byte, n)
	for i := 0; i < (n+1)/2; i++ {
		r := rune(rng.Intn('z'-'a'+1) + 'a') // 只包含小寫字母
		bytes[i] = byte(r)
		bytes[n-1-i] = byte(r)
	}
	// 隨機生成字串的子串
	length := len(bytes)
	if length == 0 {
		return "", "", 0
	}
	start := 0
	end := rng.Intn(length-start+1) + start
	subBytes := bytes[start:end]
	return string(bytes), string(subBytes), start
}

隨機測試生成的大量資料,沒必要全部儲存下來,只需要記錄每次測試時的隨機種子,如果測試出現問題,只需要那出現問題的那次隨機種子來重新測試獲得失敗樣例。


測試語句覆蓋率

測試覆蓋率通常被用來衡量測試的充分性和完整性

語句的覆蓋率是指在測試中至少被執行一次的程式碼佔總程式碼數的比例

執行go test xx_test.go xx.go -cover獲得 xx.go 的測試檔案程式碼覆蓋率摘要。

ok      command-line-arguments  0.364s  coverage: 92.9% of statements

基準測試

基準測試是測量一個程式在固定工作負載下的效能。和普通測試不同的是,預設情況下不執行任何基準測試。我們需要通過-bench命令列標誌引數手工指定要執行的基準測試函式。

  • 每個測試函式必須匯入testing包。
  • 基準測試函式名必須以 Benchmark 開頭
  • *testing.B 型別引數除了提供和*testing.T類似的方法,還有額外一些和效能測量相關的方法。它還提供了一個整數N,用於指定操作執行的迴圈次數。
func BenchmarkBruteForce(b *testing.B) {
	for i := 0; i < b.N; i++ {
		bruteForce("hello world", "world")
	}
}

在Goland中直接執行測試測試結果如下

goos: windows
goarch: amd64
pkg: MyUtils/stringMatch/bruteForce
cpu: Intel(R) Core(TM) i5-9300H CPU @ 2.40GHz
BenchmarkBruteForce
BenchmarkBruteForce-8           53356231                22.45 ns/op
PASS

示例函式

  • 以Example為函式名開頭
  • 示例函式沒有函式引數和返回值
  • 作為示例函式的函式必須以大寫字母開頭

下面為A函式的示例函式

func A() {
   // ...
}
func ExampleA() {
   // ...
}

示例函式作用:

  1. 函式的註釋會引用示例函式

  2. go test執行測試的時候也會執行示例函式測試。如果示例函式內含有// Output:格式的註釋,那麼測試工具會執行這個示例函式,然後檢查示例函式的標準輸出與註釋是否匹配。

參考資料

《go 語言聖經中文版》