Golang / GoLang Production Patterns and Web Standards Interview Questions
How do you test HTTP handlers in Go without starting a real server?
Go's net/http/httptest package provides httptest.NewRecorder() (a fake ResponseWriter) and httptest.NewServer() (a real TCP server on a random port) for testing HTTP code without network overhead.
import ( "net/http/httptest" "testing" ) // Unit test: test handler in isolation with mock dependencies func TestGetUserHandler(t *testing.T) { // Setup mock repository mockRepo := &MockUserRepo{ FindByIDFunc: func(ctx context.Context, id int) (*User, error) { return &User{ID: id, Name: "Alice"}, nil }, } svc := NewUserService(mockRepo) h := NewUserHandler(svc) // Build a request req := httptest.NewRequest(http.MethodGet, "/users/1", nil) req.SetPathValue("id", "1") // Go 1.22: set path params // Capture the response rec := httptest.NewRecorder() h.GetUser(rec, req) // Assert res := rec.Result() if res.StatusCode != http.StatusOK { t.Errorf("expected 200, got %d", res.StatusCode) } if ct := res.Header.Get("Content-Type"); ct != "application/json" { t.Errorf("expected application/json, got %s", ct) } var user User json.NewDecoder(res.Body).Decode(&user) if user.Name != "Alice" { t.Errorf("expected Alice, got %s", user.Name) } } // Integration test: use httptest.NewServer for real HTTP round-trip func TestAPIIntegration(t *testing.T) { srv := httptest.NewServer(buildRouter()) defer srv.Close() // frees the port resp, err := http.Get(srv.URL + "/health") if err != nil { t.Fatal(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Errorf("expected 200, got %d", resp.StatusCode) } }
More Related questions...