Przejdź do głównej treści
eLearner.app
Moduł 9 · Lekcja 1 z 541/50 w kursie~12 min
Lekcje modułu (1/5)

Pakiet testing

W Go testy są częścią stdlib: nie ma zewnętrznej biblioteki, nie ma frameworka do skonfigurowania. Wszystko czego potrzebujesz to plik *_test.go obok kodu, kilka funkcji TestXxx i polecenie go test.

Podstawowe konwencje

  • Pliki testowe noszą nazwę <something>_test.go i znajdują się w tym samym pakiecie co testowany kod (lub w pakiecie <name>_test w przypadku „testów czarnej skrzynki”).
  • Funkcje testowe mają dokładny podpis: func TestXxx(t *testing.T), gdzie Xxx zaczyna się od dużej litery.
  • Importujesz testing z biblioteki stdlib.
  • Brak assertEquals: używasz if got != want { t.Errorf(...) } z czasownikami fmt.
Go
// math.go
package math

func Sum(a, b int) int { return a + b }

// math_test.go
package math

import "testing"

func TestSum(t *testing.T) {
    got := Sum(2, 3)
    if got != 5 {
        t.Errorf("Sum(2,3) = %d; voglio %d", got, 5)
    }
}

Uruchom go za pomocą:

Bash
go test ./...        # all packages in the module
go test -v ./pkg     # verbose: prints test names
go test -run TestSum  # only tests matching the regex

KODEKF0 kontra KODEKF1

Oto dwa podstawowe czasowniki sygnalizujące awarię:

MetodaEfekt
KODEF0Rejestruje, ale nie kończy się niepowodzeniem (widoczne tylko z -v lub w przypadku awarii).
KODEF2Rejestruje, oznacza FAIL, kontynuuje funkcję testową.
KODEF3Podobnie jak Error z formatowaniem.
KODEF5Rejestruje, oznacza FAIL, zatrzymuje test (wywołuje runtime.Goexit).
KODEF7Podobnie jak Fatal z formatowaniem.

Ogólna zasada: użyj Fatal, gdy kontynuowanie nie ma sensu (np. nieudana konfiguracja, bezpośrednie wyłuskanie wskaźnika zerowego); w przeciwnym razie Error, który pozwala zobaczyć wszystkie awarie w jednym przebiegu.

Go
func TestOpen(t *testing.T) {
    f, err := os.Open("fixtures/sample.txt")
    if err != nil {
        t.Fatal(err) // if it doesn't open, the next steps would fail on nil
    }
    defer f.Close()
    // ... assert on content with t.Errorf
}

Konfiguracja i demontaż za pomocą t.Cleanup

Aby zwolnić zasoby na koniec testu (lub podtestu), użyj t.Cleanup zamiast defer:

Go
func TestDB(t *testing.T) {
    db := newTestDB(t)
    t.Cleanup(func() { db.Close() })
    // ... test
}

Przewaga nad defer: pomocnik tworzący db może zarejestrować czyszczenie wewnętrznie, więc dzwoniący nie muszą go pamiętać.

Testuj pomocników

Metoda t.Helper() oznacza funkcję jako „pomocniczą”: gdy test się nie powiedzie, ślad stosu pomija funkcję pomocniczą i wskazuje bezpośrednio na osobę wywołującą:

Go
func mustParseInt(t *testing.T, s string) int {
    t.Helper()
    n, err := strconv.Atoi(s)
    if err != nil {
        t.Fatalf("parse %q: %v", s, err)
    }
    return n
}

Ćwiczenia

Ćwiczenie#go.m9.l1.e1
Próby: 0Ładowanie...

Zdefiniuj funkcję TestSum, która weryfikuje Sum(2,3) == 5 za pomocą t.Errorf ze sformatowanym komunikatem.

Ładowanie edytora...

Rozwiązanie dostępne po 3 próbach

Ćwiczenie#go.m9.l1.e2
Próby: 0Ładowanie...

W TestDiv użyj t.Fatal, aby natychmiast zatrzymać test, jeśli Div zwróci nieoczekiwaną wartość.

Ładowanie edytora...

Rozwiązanie dostępne po 3 próbach

Quiz#go.m9.l1.e3
Gotowe

Jaka jest podstawowa różnica między t.Error i t.Fatal?

Go
if err != nil {
  t.???(err)
}
Opcje odpowiedzi