Integration and System Testing
Overview
Integration tests verify components work together, testing against real databases, APIs, and external services.
Test layers
unit (many, fast)
|
integration (fewer, realistic deps)
|
system/e2e (fewest, highest confidence)
HTTP Testing
import "net/http/httptest"
func TestHandler(t *testing.T) {
req := httptest.NewRequest("GET", "/users", nil)
w := httptest.NewRecorder()
handler(w, req)
if w.Code != http.StatusOK {
t.Errorf("status = %d; want 200", w.Code)
}
}Test Server
func TestAPIClient(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`{"id": 1}`))
}))
defer server.Close()
client := NewClient(server.URL)
user, err := client.GetUser(1)
// Assert...
}Database Testing
func TestUserRepository(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
db := setupTestDB(t)
t.Cleanup(func() { db.Close() })
repo := NewUserRepository(db)
// Test operations
err := repo.Create(&User{Name: "test"})
if err != nil {
t.Fatal(err)
}
}Environment-Based Tests
func TestWithEnv(t *testing.T) {
url := os.Getenv("API_URL")
if url == "" {
t.Skip("API_URL not set")
}
// Test against real API
}Docker Integration
func TestWithDocker(t *testing.T) {
if testing.Short() {
t.Skip("skipping docker test")
}
// Use testcontainers-go or similar
container, err := startPostgres()
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { container.Terminate(ctx) })
// Run tests against container
}Go 1.26 Integration Testing Upgrades
Use a two-lane CI strategy:
- Default lane (every push): fast unit + short integration.
- Full lane (main/nightly): DB containers, external API contract checks, and race detector.
# default
go test ./... -short -shuffle=on
# full
go test ./... -tags=integration -race -count=1For external APIs, always assert status + schema shape, not only status codes:
func assertUserShape(t *testing.T, body []byte) {
t.Helper()
var got map[string]any
if err := json.Unmarshal(body, &got); err != nil {
t.Fatal(err)
}
if _, ok := got["id"]; !ok {
t.Fatal("missing id")
}
}Summary
| Tool | Use Case |
|---|---|
httptest |
HTTP handlers |
| Build tags | Separate test suites |
| Env vars | External dependencies |
testing.Short() |
Skip slow tests |