INDEPENDENT NOTES ON CODE & THE WEBGO · HTML · CSS
small systems
Go / 3 minute read

Test an HTTP handler without opening a port

Use httptest to verify the contract a caller sees: status, headers, and response data.

Updated October 30, 2026Small Systems

Keep the handler easy to call

A handler is just a function with an HTTP response writer and a request. You can exercise it directly, without starting a server or finding an unused port. This is useful for checking a response contract quickly.

go
func health(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    _, _ = w.Write([]byte(`{"status":"ok"}`))
}

Assert behavior at the HTTP boundary

Put the test in a file ending in _test.go. This complete example needs encoding/json, net/http, net/http/httptest, and testing in its import block. Decoding the body checks the JSON data without depending on whitespace or key order.

go
func TestHealth(t *testing.T) {
    request := httptest.NewRequest(http.MethodGet, "/health", nil)
    recorder := httptest.NewRecorder()
    health(recorder, request)

    if recorder.Code != http.StatusOK {
        t.Fatalf("status: got %d", recorder.Code)
    }
    if got := recorder.Header().Get("Content-Type"); got != "application/json" {
        t.Fatalf("content type: got %q", got)
    }

    var body struct {
        Status string `json:"status"`
    }
    if err := json.Unmarshal(recorder.Body.Bytes(), &body); err != nil {
        t.Fatal(err)
    }
    if body.Status != "ok" {
        t.Fatalf("status field: got %q", body.Status)
    }
}

Test routing separately when it matters

Calling the handler directly does not test router behavior. If the method, path, or middleware matters, pass the request to the configured router instead. Use httptest.NewServer when you need a real HTTP client interaction, redirects, or a round trip through a network listener.

Keep the useful cases

A second successful request is less useful than a missing parameter or a malformed body. Choose cases that describe a rule someone could accidentally break. For a JSON endpoint, check invalid input, the response status, and the shape of the returned data.

Keep reading in the original documentation:
httptest package reference ↗