Einleitung: Warum Tests in Go fundamental sind
Go (Golang) wurde mit Einfachheit und Zuverlässigkeit im Hinterkopf entwickelt. Das integrierte testing-Paket ist eines der besten Werkzeuge zum Schreiben von Tests unter den modernen Sprachen. Es erfordert keine Drittanbieter-Bibliotheken für grundlegende Szenarien, ist aber dennoch leicht erweiterbar. In diesem Artikel werden wir drei Testebenen behandeln: Unit, Integration und E2E. Sie werden lernen, wie man sie schreibt, wann man sie anwendet und welche Werkzeuge man verwendet. Das Material wird sowohl für Anfänger als auch für erfahrene Go-Entwickler nützlich sein.
1. Unit-Tests in Go: die Grundlage
Unit-Tests überprüfen einzelne Funktionen oder Methoden isoliert. In Go müssen Sie lediglich eine Datei mit dem Suffix _test.go erstellen und Funktionen wie TestXxx(t *testing.T) schreiben.
Einfaches Unit-Test-Beispiel
Angenommen, wir haben eine Additionsfunktion:
// math.gopackage main
func Add(a, b int) int { return a + b}Der Test dafür:
// math_test.gopackage main
import "testing"
func TestAdd(t *testing.T) { result := Add(2, 3) expected := 5 if result != expected { t.Errorf("Add(2, 3) = %d; want %d", result, expected) }}Tabellengetriebene Tests
Die Go-Community empfiehlt die Verwendung von tabellengetriebenen Tests zum Überprüfen mehrerer Fälle:
func TestAddTable(t *testing.T) { tests := []struct { name string a, b int want int }{ {"positive", 2, 3, 5}, {"negative", -1, -2, -3}, {"zero", 0, 0, 0}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := Add(tt.a, tt.b); got != tt.want { t.Errorf("Add() = %d, want %d", got, tt.want) } }) }}Unit-Tests werden mit dem Befehl ausgeführt:
go test ./...2. Integrationstests: Überprüfung der Interaktion
Integrationstests überprüfen, wie verschiedene Teile des Systems zusammenarbeiten: Datenbank, API, Dateisystem. In Go werden sie typischerweise in separaten Dateien mit einem Build-Tag oder in einem integration-Paket platziert.
Verwendung von Build-Tags
Erstellen Sie eine Datei integration_test.go mit einem Tag:
//go:build integration
package integration
import ( "database/sql" "testing" _ "github.com/lib/pq")
func TestDatabaseConnection(t *testing.T) { dsn := "host=localhost port=5432 user=test dbname=test sslmode=disable" db, err := sql.Open("postgres", dsn) if err != nil { t.Fatalf("Fehler beim Öffnen der DB: %v", err) } defer db.Close()
err = db.Ping() if err != nil { t.Fatalf("Fehler beim Ping der DB: %v", err) }}Ausführen nur der Integrationstests:
go test -tags=integration ./...Arbeiten mit einer Testdatenbank
Für Integrationstests werden häufig testcontainers-go oder In-Memory-Datenbanken (z.B. SQLite) verwendet. Beispiel mit testcontainers:
func TestWithPostgresContainer(t *testing.T) { ctx := context.Background() pgContainer, err := postgres.RunContainer(ctx, testcontainers.WithImage("postgres:15"), postgres.WithDatabase("testdb"), ) require.NoError(t, err) defer pgContainer.Terminate(ctx)
dsn, _ := pgContainer.ConnectionString(ctx) // dsn für Verbindung verwenden}3. E2E-Tests: Überprüfung des gesamten Systems
End-to-End-Tests simulieren das Benutzerverhalten und überprüfen das gesamte System von Anfang bis Ende. In Go werden sie oft für HTTP-Dienste mit dem Paket net/http/httptest geschrieben.
E2E-Testbeispiel für eine REST-API
func TestCreateUserE2E(t *testing.T) { // S