testing.T.Run în Go

Rulează o funcție ca subtest, cu nume propriu; ideal pentru testele bazate pe un tabel de cazuri.

Sintaxă
func (t *T) Run(name string, f func(t *T)) bool

Ce face testing.T.Run

t.Run(nume, func(t *testing.T) {...}) creează un subtest. Fiecare subtest apare separat în rezultatul lui go test -v (TestReducere/fara_reducere), poate eșua independent și poate fi rulat singur cu go test -run 'TestReducere/fara'. Spațiile din nume devin _.

Tiparul cel mai folosit în Go este testul pe bază de tabel: un slice de cazuri (nume, intrare, rezultat așteptat) și o buclă care apelează t.Run pentru fiecare. Un t.Fatal într-un subtest oprește doar acel subtest.

Parametri

Parametru Descriere
name Numele subtestului.
f Funcția subtestului; primește propriul *testing.T.

Ce returnează

true dacă subtestul a trecut (sau rulează în paralel), altfel false.

Exemple

Exemplul 1: Test pe bază de tabel

// fișierul reducere.go
package magazin

// Reducere returnează procentul de reducere: 5% de la 200 lei, 10% de la 500 lei.
func Reducere(total float64) int {
    switch {
    case total >= 500:
        return 10
    case total >= 200:
        return 5
    default:
        return 0
    }
}

// fișierul reducere_test.go
package magazin

import "testing"

func TestReducere(t *testing.T) {
    cazuri := []struct {
        nume  string
        total float64
        vrem  int
    }{
        {"fara reducere", 50, 0},
        {"exact 200", 200, 5},
        {"intre praguri", 350, 5},
        {"peste 500", 640, 10},
    }
    for _, c := range cazuri {
        t.Run(c.nume, func(t *testing.T) {
            if got := Reducere(c.total); got != c.vrem {
                t.Errorf("Reducere(%v) = %d, aștept %d", c.total, got, c.vrem)
            }
        })
    }
}

Rezultatul în terminal (timpii diferă la fiecare rulare)

$ go test -v
=== RUN   TestReducere
=== RUN   TestReducere/fara_reducere
=== RUN   TestReducere/exact_200
=== RUN   TestReducere/intre_praguri
=== RUN   TestReducere/peste_500
--- PASS: TestReducere (0.00s)
    --- PASS: TestReducere/fara_reducere (0.00s)
    --- PASS: TestReducere/exact_200 (0.00s)
    --- PASS: TestReducere/intre_praguri (0.00s)
    --- PASS: TestReducere/peste_500 (0.00s)
PASS
ok  	magazin	0.329s

Exemplul 2: Rularea unui singur subtest

Același cod; după / scrii (o parte din) numele subtestului, cu _ în loc de spații.

// aceleași fișiere reducere.go și reducere_test.go

Rezultatul în terminal (timpii diferă la fiecare rulare)

$ go test -v -run TestReducere/exact_200
=== RUN   TestReducere
=== RUN   TestReducere/exact_200
--- PASS: TestReducere (0.00s)
    --- PASS: TestReducere/exact_200 (0.00s)
PASS
ok  	magazin	0.273s

Greșeli frecvente

  • Dai nume identice subtestelor. Go adaugă #01, #02 și devine greu de găsit cazul care a eșuat; dă nume unice și descriptive.
  • Folosești t-ul testului părinte în interiorul subtestului (func(_ *testing.T) { t.Errorf(...) }). Eroarea se atribuie părintelui; folosește parametrul subtestului.

Comenzi înrudite

  • testing.T: Tipul primit de fiecare funcție de test; prin el raportezi erori, scrii mesaje și controlezi testul.
  • testing.T.Parallel: Anunță că testul poate rula în paralel cu alte teste paralele, ca suita să se termine mai repede.
  • testing.T.Error: Marchează testul ca eșuat și scrie un mesaj, dar lasă testul să continue (Errorf formatează ca Printf).
  • testing.T.Helper: Marchează o funcție ca ajutătoare, ca erorile raportate din ea să arate linia din test care a apelat-o.