go 46 lines · 1 tab

Table-driven tests for HTTP handlers with httptest

Leah Thompson Jan 2026
1 tab
package api_test

import (
  "encoding/json"
  "net/http"
  "net/http/httptest"
  "strings"
  "testing"
)

type createThingReq struct {
  Name string `json:"name"`
}

func TestCreateThing(t *testing.T) {
  cases := []struct {
    name   string
    body   string
    status int
  }{
    {name: "missing", body: `{}`, status: http.StatusBadRequest},
    {name: "ok", body: `{"name":"demo"}`, status: http.StatusCreated},
  }

  for _, tc := range cases {
    t.Run(tc.name, func(t *testing.T) {
      r := httptest.NewRequest(http.MethodPost, "/things", strings.NewReader(tc.body))
      w := httptest.NewRecorder()

      handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        var req createThingReq
        if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.Name == "" {
          http.Error(w, "bad request", http.StatusBadRequest)
          return
        }
        w.WriteHeader(http.StatusCreated)
      })

      handler.ServeHTTP(w, r)

      if w.Code != tc.status {
        t.Fatalf("got status %d, want %d", w.Code, tc.status)
      }
    })
  }
}
1 file · go Explain with highlit

Go’s table-driven tests are one of the best “boring but effective” practices. For handlers, I use httptest.NewRecorder and httptest.NewRequest so tests run fast without networking. Each case specifies method, path, body, expected status, and sometimes expected JSON keys. The big win is that you can add new edge cases as rows in a table instead of copying/pasting test bodies. I also prefer testing behavior, not implementation: assert status codes, headers, and response shapes rather than internal function calls. When I need stable JSON comparisons, I decode into map[string]any and compare keys. This pattern scales nicely as your API grows and catches regressions early, especially around validation and error handling.


Related snips

Share this code

Here's the card — post it anywhere.

Table-driven tests for HTTP handlers with httptest — share card
Link copied