Go 測試的一個小風格(自認為)指南。關於寫好測試的文章比我在這寫的要多的多。但我寫的主要是關於風格而不是技術。## 使用 table-drive 測試,並始終使用 tt 作為測試案例嘗試在可行的情況下使用 table-driven 測試,但當不可行時,可以複製一些代碼;不要強制使用它(例如,有時候除了一兩個案例之外,更容易為這之外的情況編寫一個 table-driven 的測試;實際情況就是如此)。始終為一個測試案例使用相同變數名會使它更容易為大量代碼工作。你不必使用 tt,但是在 Go 標準庫中它是最常用的( 564 次對比 tc 用了 116 次)。可以看看 [TableDrivenTests](https://github.com/golang/go/wiki/TableDrivenTests)。例如:```gotests := []struct {// ...}{}for _, tt := range tests {}```## 使用子測試使用子測試可以從 table 中運行一個單獨的測試,且可以容易的看出哪個測試完全失敗了。由於子測試是比較新的版本( Go 1.7,2016年10月),所以許多現存的測試不能使用它們(子測試)。如果測試內容很明顯,我傾向於簡單地使用測試編號;如果不明顯或有很多測試案例,就添加一個測試名。可以看下[使用子測試和子基準](https://blog.golang.org/subtests)例如:```gotests := []struct {// ...}{}for i, tt := range tests {t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {got := TestFunction(tt.input)if got != tt.want {t.Errorf("failed for %v ...", tt.input)}})}```## 不要忽略錯誤我經常看到在測試中有人忽略錯誤。這是不好的想法並且使失敗的測試混亂。例如:```gogot, err := Fun()if err != nil { t.Fatalf("unexpected error: %v", err)}```或者:```gogot, err := Fun()if err != tt.wantErr { t.Fatalf("wrong error\ngot: %v\nwant: %v", err, tt.wantErr)}```我經常使用 [ErroContains](https://github.com/Teamwork/test/blob/859eda3cd87ed7713df79c5bb2b2a90601ad0524/test.go#L13-L26),它是一個很有用的協助函數對測試錯誤資訊(避免一些 `if err != nil && [..]`)。## 檢查你的測試作為常規代碼測試代碼也會失敗,錯誤,所以需要維護。如果你認為運行 linter 對你的正規代碼是值得的,那麼對你的測試回合也是一樣值得的。(例如:go vet, errcheck 等)。## 使用 want 和 gotwant 比 expected 短,got 比 actual 短。短命名總是有優勢的,IMHO,並且特別有利於對齊輸出(看下面的例子)。例如:```gocases := []struct { want string wantCode int}{}```## 添加有用的,可對齊的資訊當一個測試失敗伴隨著無用的錯誤資訊,或者是一個混亂的錯誤資訊,使你很難看出準確的錯誤時是很惱人的。這不是特別有用:```got.Errorf("wrong output: %v", got)```當測試失敗時,它告訴我們得到了錯誤輸出,但是我們想要得到的是什麼呢?這個就比較好:```goname := "test foo"got := "this string!"want := "this string"t.Errorf("wrong output for %v, want %v; got %v", name, got, want)```下面這個很難看到準確的失敗:```--- FAIL: TestX (0.00s)a_test.go:9: wrong output for test foo, want this string!; got this string```當把它對齊,就很容易了:```goname := "test foo"want := "this string"t.Run(name, func(t *testing.T) { got := "this string!" t.Errorf("wrong output\ngot: %q\nwant: %q", got, want)})``````--- FAIL: TestX (0.00s)--- FAIL: TestX/test_foo (0.00s)a_test.go:10: wrong outputgot: "this string!"want: "this string"```注意 `got:` 後面的倆個空格,是為了和 `want` 對齊的。如果我使用 `expected` 就要使用6個空格。我還傾向於使用 `%q` 或 `%#v`,因為這會很清楚的顯示後面的空白或不可列印字元。使用 diff 比較較大的對象;例如用 [go-cmp](https://github.com/google/go-cmp):```goif d := cmp.Diff(got, tt.want); d != "" {t.Errorf("(-got +want)\n:%s", d)}``````--- FAIL: TestParseFilter (0.00s)--- FAIL: TestParseFilter/alias (0.00s)query_test.go:717: (-got +want):{jsonapi.Filter}.Alias:-: "fail"+: "alias"```## 搞清楚要測試什麼有時我看到一些測試,我困惑 “這是在測試什嗎?” 如果測試失敗的原因不名這會令人特別困惑。應該改哪?測試正確嗎?例如:```gocases := []struct {name string}{{"space after @",},{"unicode space before @",},// ...}```如果添加 `name` 到存在的測試案例一定比注釋要更有用。## 反饋你可以給我發郵件: [martin@arp242.ent](martin@arp242.net) 或者 [提交一個 GitHub 問題](https://github.com/Carpetsmoker/arp242.net/issues/new)反饋,提問等。
via: https://arp242.net/weblog/go-testing-style.html
作者:Martin Tournoij 譯者:themoonbear 校對:polaris1119
本文由 GCTT 原創編譯,Go語言中文網 榮譽推出
本文由 GCTT 原創翻譯,Go語言中文網 首發。也想加入譯者行列,為開源做一些自己的貢獻嗎?歡迎加入 GCTT!
翻譯工作和譯文發表僅用於學習和交流目的,翻譯工作遵照 CC-BY-NC-SA 協議規定,如果我們的工作有侵犯到您的權益,請及時聯絡我們。
歡迎遵照 CC-BY-NC-SA 協議規定 轉載,敬請在本文中標註並保留原文/譯文連結和作者/譯者等資訊。
文章僅代表作者的知識和看法,如有不同觀點,請樓下排隊吐槽
119 次點擊