Stage 1 · Code
Building Web Services
Testing HTTP Handlers
A handler is more than business logic. Test the real HTTP surface with `httptest` so you prove status codes, headers, bodies, and routing all behave the way clients will actually see them.
Why Handler Tests Matter
Suppose your deployment-creation function works perfectly in isolation. It validates input, stores a record, and returns the right struct. You still do not know whether the handler built around it uses the right status code, sets Content-Type, reads the body correctly, wires the route correctly, or returns the JSON shape clients depend on. That gap is exactly why handler-level tests matter.
In other words, business-logic tests answer 'does the inner rule work?' Handler tests answer 'does the HTTP surface work the way a real client experiences it?' Both are valuable, and neither fully replaces the other.
A client cannot see your private helper functions. It can see status codes, headers, body bytes, routes, and methods. Handler tests should assert those directly.
Testing One Handler Directly
net/http/httptest gives you a fake request and a fake response recorder. That lets you call a handler directly in memory, without starting a real network listener. For many tests, that is the fastest and clearest level to begin with.
Testing the Whole Server Shape
Direct handler tests are excellent, but sometimes you want one step more realism. httptest.NewServer() starts a real HTTP server on a temporary local address. Your test then uses a real HTTP client against that server. This catches problems in routing and full request flow that a direct function call might not reveal as clearly.
Most failures are easier to debug in a direct handler test. Reach for httptest.NewServer() when you specifically want to prove the server, routes, and client interaction as one whole path.
Tracing the Assertions
The value of a handler test is not just that it is green. It is that each assertion tells you something precise about the contract your clients rely on.
request: POST /deployments
body: {"service":"billing-api","version":"1.4.2","environment":"staging"}
expect status: 201
expect header: Content-Type = application/json
expect body field: id = dep-001
expect body field: status = queuedA strong handler test behaves like a careful client. It checks what a real caller can observe and depend on.
Quiz and Practice
What does `httptest.NewRecorder()` represent in a handler test?
Hands-On Project
Complete the test so it proves `GET /deployments/{id}` returns status `404` and an error body when the deployment does not exist.
Summary and Key Takeaways
httptest.NewRequest()builds the request your handler will receive.httptest.NewRecorder()captures status code, headers, and body so you can assert the HTTP contract directly.httptest.NewServer()is useful when you want to test routing and full client-server interaction together.- Handler tests complement business-logic tests by checking what clients can actually observe.
- Good assertions are specific: they name the exact status code, header, and response fields the API promises.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.