Skip to main content

How to test a Go HTTP API with httptest

Test a Go HTTP API with the standard library: write a handler, capture responses with httptest.ResponseRecorder, run end-to-end tests with httptest.NewServer, and use table-driven cases.

Difficulty
Intermediate
Duration
45 minutes
Steps
6

What httptest gives you

Go's standard library includes net/http/httptest, which lets you test HTTP handlers without opening a real network port. A ResponseRecorder captures what a handler writes, and httptest.NewServer spins up a real but local server for end-to-end tests. Combined with Go's built-in testing package, you get fast, dependency-free API tests.

Prerequisites

  • Go 1.21 or later
  • Basic Go and HTTP knowledge

Steps

1. Set up the module

mkdir api && cd api
go mod init example.com/api

2. Write an HTTP handler

package api

import (
    "encoding/json"
    "net/http"
)

func HealthHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
}

3. Test with ResponseRecorder

The recorder captures the response so you can assert on it directly.

package api

import (
    "net/http"
    "net/http/httptest"
    "testing"
)

func TestHealthHandler(t *testing.T) {
    req := httptest.NewRequest(http.MethodGet, "/health", nil)
    rec := httptest.NewRecorder()

    HealthHandler(rec, req)

    if rec.Code != http.StatusOK {
        t.Fatalf("got status %d, want 200", rec.Code)
    }
}

4. Test with a test server

For a full round trip through the HTTP stack, start a test server.

srv := httptest.NewServer(http.HandlerFunc(HealthHandler))
defer srv.Close()
resp, _ := http.Get(srv.URL)

5. Use table-driven cases

Drive multiple requests from a slice of structs to cover many paths and methods concisely.

6. Run tests and coverage

go test ./...
go test -cover ./...

Verification

Run go test ./... and confirm the handler test passes. Add a case asserting the response body contains "status":"ok". Change the handler to return a wrong status and confirm the test fails with a clear message.

Next Steps

Test middleware, inject dependencies through the handler's struct, add table-driven cases for error paths, and run go test -race ./... in continuous integration.

Prerequisites

  • Go 1.21+ installed
  • Basic Go and HTTP knowledge

Steps

  • 1
    Set up the module
  • 2
    Write an HTTP handler
  • 3
    Test with ResponseRecorder
  • 4
    Test with a test server
  • 5
    Use table-driven cases
  • 6
    Run tests and coverage

Category

Testing