Integrationstests von Go mit Docker: Vollständiger Leitfaden
\n\nIntegrationstests sind ein kritisch wichtiger Schritt in der Entwicklung, insbesondere in der Welt der Mikroservices und verteilten Systeme. Go (Golang) in Kombination mit Docker bietet leistungsstarke und elegante Werkzeuge zur Erstellung zuverlässiger Integrationstests. In diesem Artikel werden wir erläutern, wie man die Umgebung einrichtet, Tests für die Interaktion mit Datenbanken und externen Diensten schreibt, unter Verwendung von Docker, testcontainers-go und der Standardbibliothek testing.
1. Warum Docker für Integrationstests?
\n\nTraditionelle Modultests (Unit-Tests) isolieren die Logik, überprüfen jedoch nicht die Interaktion mit realen Abhängigkeiten: Datenbanken, Warteschlangen, APIs. Docker löst dieses Problem, indem es Folgendes ermöglicht:
\n- \n
- Isolierung der Umgebung: Jeder Test startet einen sauberen Container und schließt Zustandskonflikte aus. \n
- Wiederholbarkeit: Gleiche Umgebung auf dem lokalen Rechner und in CI/CD. \n
- Schnelle Bereitstellung: Container starten in Sekunden. \n
- Einfache Bereinigung: Nach dem Test wird der Container zerstört. \n
Wir werden die Bibliothek testcontainers-go verwenden – sie bietet eine hochwertige API zur Verwaltung des Lebenszyklus von Containern direkt aus dem Testcode.
2. Projekteinrichtung und Installation von Abhängigkeiten
\n\nWir erstellen einen einfachen HTTP-Server in Go, der Daten in PostgreSQL speichert. Anschließend schreiben wir einen Integrationstest, der den Endpunkt überprüft.
\n\nProjektstruktur:
\nmyapp/\n├── main.go\n├── go.mod\n├── go.sum\n├── handlers/\n│ └── user.go\n└── integration_test.go\n\nSchritt 1: Modul initialisieren und testcontainers installieren:
\ngo mod init myapp\ngo get github.com/testcontainers/testcontainers-go\ngo get github.com/testcontainers/testcontainers-go/modules/postgres\ngo get github.com/lib/pq\ngo get github.com/stretchr/testify/assert\n\nSchritt 2: Wir schreiben einen einfachen Handler in handlers/user.go:
package handlers\n\nimport (\n "database/sql"\n "encoding/json"\n "net/http"\n)\n\ntype User struct {\n Name string `json:"name"`\n Age int `json:"age"`\n}\n\nfunc CreateUser(db *sql.DB) http.HandlerFunc {\n return func(w http.ResponseWriter, r *http.Request) {\n var user User\n if err := json.NewDecoder(r.Body).Decode(&user); err != nil {\n http.Error(w, err.Error(), http.StatusBadRequest)\n return\n }\n _, err := db.Exec("INSERT INTO users (name, age) VALUES ($1, $2)", user.Name, user.Age)\n if err != nil {\n http.Error(w, err.Error(), http.StatusInternalServerError)\n return\n }\n w.WriteHeader(http.StatusCreated)\n json.NewEncoder(w).Encode(user)\n }\n}\n\n3. Integrationstest mit Docker schreiben
\n\nJetzt kommt der spannendste Teil – der Test, der PostgreSQL in Docker startet, eine Tabelle erstellt, unseren Server startet und seine Funktion überprüft.
\n\nDatei integration_test.go:
package myapp\n\nimport (\n "bytes"\n "context"\n "encoding/json"\n "net/http"\n "net/http/httptest"\n "testing"\n\n "myapp/handlers"\n\n "github.com/lib/pq"\n "github.com/stretchr/testify/assert"\n "github.com/testcontainers/testcontainers-go"\n "github.com/testcontainers/testcontainers-go/modules/postgres"\n "github.com/testcontainers/testcontainers-go/wait"\n)\n\nfunc TestCreateUserIntegration(t *testing.T) {\n ctx := context.Background()\n\n // 1. PostgreSQL-Container starten\n pgContainer, err := postgres.RunContainer(ctx,\n testcontainers.WithImage("postgres:15-alpine"),\n postgres.WithDatabase("testdb"),\n postgres.WithUsername("test"),\n postgres.