Testen in Go: Unit, Integration, E2E von A bis Z

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Warum Testen in Go eine Notwendigkeit ist

\n

Go (Golang) ist eine moderne Programmiersprache, die für den Bau zuverlässiger und skalierbarer Systeme entwickelt wurde. Doch selbst der eleganteste Code ist nicht vor Fehlern gefeit. Deshalb ist das Testen ein wesentlicher Bestandteil der Entwicklung in Go. Das integrierte Paket testing bietet leistungsstarke Werkzeuge zum Schreiben von Unit-Tests, Integrationstests und sogar End-to-End (E2E)-Prüfungen.

\n

In diesem Artikel werden wir alle Testebenen in Go durchgehen: von einfachen Unit-Tests bis hin zu komplexen E2E-Szenarien. Sie erfahren, wie Sie Tests richtig strukturieren, Mocks verwenden, table-driven Tests schreiben und Integrationstests mit echten Abhängigkeiten einrichten. Das Material ist sowohl für Anfänger als auch für erfahrene Entwickler nützlich, die ihr Wissen systematisieren möchten.

\n\n

1. Unit-Testing in Go: Die Grundlage

\n

Unit-Tests überprüfen die Arbeit einzelner Funktionen oder Methoden isoliert von externen Abhängigkeiten. In Go wird dafür das Standardpaket testing verwendet. Grundregeln: Testdateien müssen *_test.go heißen, und Testfunktionen müssen mit Test beginnen.

\n\n

1.1. Ein einfacher Unit-Test

\n

Betrachten wir eine Funktion zur Addition zweier Zahlen:

\n
// math.go\npackage math\n\nfunc Add(a, b int) int {\n    return a + b\n}
\n

Der Test dafür:

\n
// math_test.go\npackage math\n\nimport "testing"\n\nfunc TestAdd(t *testing.T) {\n    result := Add(2, 3)\n    expected := 5\n    if result != expected {\n        t.Errorf("Add(2, 3) = %d; want %d", result, expected)\n    }\n}
\n

Tests ausführen: go test ./... oder go test -v für detaillierte Ausgabe.

\n\n

1.2. Table-Driven Tests (Tabellengesteuerte Tests)

\n

Die Go-Community verwendet häufig den table-driven Ansatz, um mehrere Fälle zu prüfen:

\n
func TestAddTableDriven(t *testing.T) {\n    tests := []struct {\n        name string\n        a, b int\n        want int\n    }{\n        {"positive", 2, 3, 5},\n        {"negative", -1, -2, -3},\n        {"zero", 0, 0, 0},\n    }\n    for _, tt := range tests {\n        t.Run(tt.name, func(t *testing.T) {\n            if got := Add(tt.a, tt.b); got != tt.want {\n                t.Errorf("Add() = %d, want %d", got, tt.want)\n            }\n        })\n    }\n}
\n

Dieser Ansatz macht Tests leicht lesbar und erweiterbar.

\n\n

1.3. Testen mit Fehlern

\n

Für Funktionen, die Fehler zurückgeben, verwenden Sie t.Fatal oder t.Errorf:

\n
func TestDivide(t *testing.T) {\n    _, err := Divide(10, 0)\n    if err == nil {\n        t.Fatal("expected error for division by zero")\n    }\n}
\n\n

2. Integrationstests: Arbeiten mit Abhängigkeiten

\n

Integrationstests überprüfen die Interaktion von Komponenten: Datenbanken, APIs, Dateisysteme. In Go werden sie üblicherweise mit Build-Tags oder einer separaten Paketstruktur von Unit-Tests getrennt.

\n\n

2.1. Verwendung von Build-Tags

\n

Erstellen Sie eine Datei mit dem Tag //go:build integration am Anfang:

\n
//go:build integration\n\npackage db\n\nimport (\n    "testing"\n    "database/sql"\n    _ "github.com/lib/pq"\n)\n\nfunc TestPostgresConnection(t *testing.T) {\n    dsn := "host=localhost port=5432 user=test password=test dbname=test sslmode=disable"\n    db, err := sql.Open("postgres", dsn)\n    if err != nil {\n        t.Fatalf("failed to open db: %v", err)\n    }\n    defer db.Close()\n    \n    if err := db.Ping(); err != nil {\n        t.Fatalf("failed to ping db: %v", err)\n    }\n}
\n

Nur Integrationstests ausführen: go test -tags=integration ./...

\n\n

2.2. Mocks und Stubs

\n

Verwenden Sie Interfaces und Mocks zur Isolation von Tests. Beispiel mit der beliebten Bibliothek gomock:

\n
// user.go\ntype UserRepository interface {\n    GetUser(id int) (*Us                

Blogs

Buchempfehlungen