Ana içeriğe geç
Modül 9 · Ders 2 ders 5Kurstaki 42/50~14 min
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

Go
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:

  1. Anonim yapının bir kesiti olağan alanlarla birlikte: name, girdiler, beklenen çıktı (ve belki de beklenen bir hata).
  2. for _, tc := range cases — yürütme döngüsü.
  3. 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.Fatal kullanılmadığı sürece).
  • Komut satırı filtreleme: go test -run TestAbs/neg yalnızca bu durumda çalışır.
  • İsteğe bağlı paralellik: paralelleştirmek için işlevin içinde t.Parallel() öğesini çağırın.
Bash
go test -v -run TestAbs/neg

Beklenen hataların olduğu durumlar

Go
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:

Go
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".
  • -run ile 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

Egzersiz#go.m9.l2.e1
Denemeler: 0Yükleniyor…

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.

Düzenleyici yükleniyor…

3 denemeden sonra çözüm mevcut

Egzersiz#go.m9.l2.e2
Denemeler: 0Yükleniyor…

Her durumu adlandırılmış bir alt teste dönüştürmek için t.Run'u tc.name ile ekleyin.

Düzenleyici yükleniyor…

3 denemeden sonra çözüm mevcut

Quiz#go.m9.l2.e3
Hazır

Tablo odaklı modelin N ayrı Test fonksiyonuna göre temel avantajı nedir?

Go
for _, tc := range cases {
  t.Run(tc.name, func(t *testing.T) { ... })
}
Cevap seçenekleri