Modül dersleri (2/5)
Tabloya dayalı testler
Tablo odaklı testler Go'nun deyimsel modelidir: N ayrı TestThisSpecificCase işlevi yazmak yerine, bir vaka dilimi bildirir ve yinelersiniz. BİR onaylama bloğu vardır ve test verileri mantıktan ayrılmıştır.
Temel desen
func TestAbs(t *testing.T) {
cases := []struct {
name string
in int
want int
}{
{"pos", 3, 3},
{"neg", -3, 3},
{"zero", 0, 0},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
if got := Abs(tc.in); got != tc.want {
t.Errorf("Abs(%d) = %d; voglio %d", tc.in, got, tc.want)
}
})
}
}Üç bileşen:
- Anonim yapının bir kesiti olağan alanlarla birlikte:
name, girdiler, beklenen çıktı (ve belki de beklenen bir hata). for _, tc := range cases— yürütme döngüsü.t.Run(tc.name, func(t *testing.T) { ... })— her durum kendi adı taşıyan bir alt test haline gelir.
Neden t.Run?
t.Run aşağıdakileri içeren bir alt test oluşturur:
- Çıktıda gösterilen kişisel ad:
TestAbs/pos,TestAbs/neg, ... - Kendi
t *testing.T: bir durumdaki başarısızlık diğerlerini durdurmaz (t.Fatalkullanılmadığı sürece). - Komut satırı filtreleme:
go test -run TestAbs/negyalnızca bu durumda çalışır. - İsteğe bağlı paralellik: paralelleştirmek için işlevin içinde
t.Parallel()öğesini çağırın.
go test -v -run TestAbs/negBeklenen hataların olduğu durumlar
cases := []struct {
name string
in string
want int
wantErr bool
}{
{"ok", "42", 42, false},
{"bad", "x", 0, true},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got, err := Atoi(tc.in)
if (err != nil) != tc.wantErr {
t.Fatalf("err = %v, wantErr = %v", err, tc.wantErr)
}
if !tc.wantErr && got != tc.want {
t.Errorf("got %d, want %d", got, tc.want)
}
})
}Döngü kapatma tuzağı (Go 1.22 öncesi)
Go 1.22'den önceki sürümlerde, tc değişkeni yinelemeler arasında paylaşılıyordu: t.Parallel() içinde t.Run çağrılması tüm alt testlerin aynı son duruma karşı çalıştırılmasına neden oldu. Düzeltme şuydu:
for _, tc := range cases {
tc := tc // local rebind (pre-1.22)
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
// ...
})
}Vakaların adlandırılması
En iyi uygulamalar:
- Kısa ama çağrıştırıcı bir ad:
"empty input","too large","negative". -runile kolayca filtrelemek (veya alt çizgi kullanmak) istiyorsanız boşluk kullanmayın.- Her zaman bir "mutlu yol" durumu, bir "kenar" durumu (sıfır, boş) ve en az bir hata durumu ekleyin.
Egzersizler
Abs'yi (pozitif, negatif, sıfır) test etmek için 3 durumla doldurulmuş, içinde ve istediğiniz alanlarla anonim yapının bir vaka dilimini tanımlayın.
3 denemeden sonra çözüm mevcut
Her durumu adlandırılmış bir alt teste dönüştürmek için t.Run'u tc.name ile ekleyin.
3 denemeden sonra çözüm mevcut
Tablo odaklı modelin N ayrı Test fonksiyonuna göre temel avantajı nedir?
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) { ... })
}