Getting started
Install apitest, write a first test, and read what a failure looks like.
Install
apitest requires Go 1.23 or later.
go get github.com/steinfletcher/apitestapitest follows semantic versioning. Releases are published on GitHub.
Write a handler
Any http.Handler or handler function can be tested. This one greets the caller by name.
func helloHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]string{
"message": "hello " + r.URL.Query().Get("name"),
})
}
Write a test
Pass the handler to apitest, describe the request, then call Expect(t) and describe the response you expect. End() runs the test.
func TestHello(t *testing.T) {
apitest.New().
HandlerFunc(helloHandler).
Get("/hello").
Query("name", "gopher").
Expect(t).
Status(http.StatusOK).
Header("Content-Type", "application/json").
Body(`{"message": "hello gopher"}`).
End()
}
No server is started. apitest calls the handler's ServeHTTP method directly with an httptest.ResponseRecorder, so tests are fast and need no free ports.
Run it
go test ./...Reading a failure
apitest checks every expectation and reports all failures, not just the first. Suppose the test above expected 201 Created and the body {"message": "hello world"}. The output names each mismatch:
--- FAIL: TestHello (0.00s)
assert.go:105:
Error Trace: hello_test.go:18
Error: Not equal:
expected: 201
actual : 200
Test: TestHello
Messages: Status code 200 not equal to 201
assert.go:105:
Error Trace: hello_test.go:18
Error: Not equal:
expected: map[string]interface {}{"message":"hello world"}
actual : map[string]interface {}{"message":"hello gopher"}
Diff:
--- Expected
+++ Actual
@@ -1,4 +1,4 @@
(map[string]interface {}) (len=1) {
- (string) (len=7) "message": (string) (len=11) "hello world"
+ (string) (len=7) "message": (string) (len=12) "hello gopher"
}
Test: TestHelloThe body was compared as JSON, so the diff shows the decoded values rather than raw strings. Key order and whitespace never cause a failure.