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.goi znajdują się w tym samym pakiecie co testowany kod (lub w pakiecie<name>_testw przypadku „testów czarnej skrzynki”). - Funkcje testowe mają dokładny podpis:
func TestXxx(t *testing.T), gdzieXxxzaczyna się od dużej litery. - Importujesz
testingz biblioteki stdlib. - Brak
assertEquals: używaszif got != want { t.Errorf(...) }z czasownikamifmt.
// 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ą:
go test ./... # all packages in the module
go test -v ./pkg # verbose: prints test names
go test -run TestSum # only tests matching the regexKODEKF0 kontra KODEKF1
Oto dwa podstawowe czasowniki sygnalizujące awarię:
| Metoda | Efekt |
|---|---|
| KODEF0 | Rejestruje, ale nie kończy się niepowodzeniem (widoczne tylko z -v lub w przypadku awarii). |
| KODEF2 | Rejestruje, oznacza FAIL, kontynuuje funkcję testową. |
| KODEF3 | Podobnie jak Error z formatowaniem. |
| KODEF5 | Rejestruje, oznacza FAIL, zatrzymuje test (wywołuje runtime.Goexit). |
| KODEF7 | Podobnie 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.
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:
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ą:
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
Zdefiniuj funkcję TestSum, która weryfikuje Sum(2,3) == 5 za pomocą t.Errorf ze sformatowanym komunikatem.
Rozwiązanie dostępne po 3 próbach
W TestDiv użyj t.Fatal, aby natychmiast zatrzymać test, jeśli Div zwróci nieoczekiwaną wartość.
Rozwiązanie dostępne po 3 próbach
Jaka jest podstawowa różnica między t.Error i t.Fatal?
if err != nil {
t.???(err)
}