HTTP Tests
The testing package in Nimbus provides a fluent TestClient that sends requests directly to your application without spinning up a network listener. Tests run entirely in-process and fast.
Creating a TestClient: testing.New(app)
Pass your *nimbus.App directly to testing.New(app). It automatically ensures the application is warmed up in ModeTest.
import ntest "github.com/CodeSyncr/nimbus/testing"
app := setupTestApp()
client := ntest.New(app)
Fluent Assertions
Chain requests, authentication, and assertions fluently:
func TestUserAPI(t *testing.T) {
app := setupTestApp()
client := ntest.New(app)
// Fluent GET with assertions
client.Get("/api/users").
WithBearerToken("secret-token").
AssertOK(t).
AssertHeader(t, "Content-Type", "application/json").
AssertJSONPath(t, "status", "success")
// Fluent POST JSON
client.PostJSON("/api/users", map[string]string{"name": "Alice"}).
AssertCreated(t).
AssertJSONPath(t, "data.name", "Alice")
}
Direct HTTP Handler Testing: app.ServeHTTP
Because *nimbus.App directly implements standard net/http.Handler, you can test it directly with httptest.ResponseRecorder or pass it to httptest.NewServer(app):
func TestHealthDirect(t *testing.T) {
app := setupTestApp()
req := httptest.NewRequest("GET", "/health", nil)
rec := httptest.NewRecorder()
app.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("expected 200, got %d", rec.Code)
}
}
GET requests
func TestListUsers(t *testing.T) {
client := nimbustest.NewTestClient(setupTestApp().Router)
resp := client.Get("/users")
if resp.Code != 200 {
t.Fatalf("expected 200, got %d", resp.Code)
}
}
POST requests
Post(path, body) sends a POST with Content-Type: application/json. Pass nil for an empty body.
func TestCreatePost(t *testing.T) {
client := nimbustest.NewTestClient(setupTestApp().Router)
body := []byte(`{"title":"Hello","content":"World"}`)
resp := client.Post("/posts", body)
if resp.Code != 201 {
t.Fatalf("expected 201, got %d", resp.Code)
}
}
PUT and DELETE with Do
Use client.Do(req) for PUT, PATCH, DELETE, or any method with custom headers.
func TestUpdateUser(t *testing.T) {
client := nimbustest.NewTestClient(setupTestApp().Router)
body := bytes.NewReader([]byte(`{"name":"Bob"}`))
req := httptest.NewRequest(http.MethodPut, "/users/1", body)
req.Header.Set("Content-Type", "application/json")
resp := client.Do(req)
if resp.Code != 200 {
t.Fatalf("expected 200, got %d", resp.Code)
}
}
func TestDeleteUser(t *testing.T) {
client := nimbustest.NewTestClient(setupTestApp().Router)
req := httptest.NewRequest(http.MethodDelete, "/users/1", nil)
resp := client.Do(req)
if resp.Code != 204 {
t.Fatalf("expected 204, got %d", resp.Code)
}
}
Asserting JSON response bodies
Read the response body from the recorder and unmarshal it.
func TestHealthJSON(t *testing.T) {
client := nimbustest.NewTestClient(setupTestApp().Router)
resp := client.Get("/health")
var result map[string]string
json.Unmarshal(resp.Body.Bytes(), &result)
if result["status"] != "ok" {
t.Errorf("expected status ok, got %s", result["status"])
}
}
Asserting headers
func TestContentType(t *testing.T) {
client := nimbustest.NewTestClient(setupTestApp().Router)
resp := client.Get("/health")
ct := resp.Header().Get("Content-Type")
if ct != "application/json" {
t.Errorf("expected application/json, got %s", ct)
}
}
Testing authenticated routes
Set authorization headers on the request before sending it through Do.
func TestProtectedRoute(t *testing.T) {
client := nimbustest.NewTestClient(setupTestApp().Router)
req := httptest.NewRequest(http.MethodGet, "/admin/dashboard", nil)
req.Header.Set("Authorization", "Bearer test-token-123")
resp := client.Do(req)
if resp.Code != 200 {
t.Fatalf("expected 200, got %d", resp.Code)
}
}
Testing middleware
Register middleware on a test router and verify its effect (e.g. CORS headers, rate limiting).
func TestCORSMiddleware(t *testing.T) {
app := nimbus.New()
app.Router.Use(middleware.CORS("https://example.com"))
app.Router.Get("/ping", func(c *http.Context) error {
return c.String(200, "pong")
})
client := nimbustest.NewTestClient(app.Router)
resp := client.Get("/ping")
origin := resp.Header().Get("Access-Control-Allow-Origin")
if origin != "https://example.com" {
t.Errorf("expected CORS origin, got %s", origin)
}
}
Complete example test file
package main
import (
"encoding/json"
"testing"
"github.com/CodeSyncr/nimbus"
"github.com/CodeSyncr/nimbus/middleware"
nimbustest "github.com/CodeSyncr/nimbus/testing"
)
func setupTestApp() *nimbus.App {
app := nimbus.New()
app.Router.Use(middleware.Recover())
app.Router.Get("/health", healthHandler)
app.Router.Get("/users", listUsersHandler)
app.Router.Post("/users", createUserHandler)
return app
}
func TestHealth(t *testing.T) {
client := nimbustest.NewTestClient(setupTestApp().Router)
resp := client.Get("/health")
if resp.Code != 200 {
t.Fatalf("expected 200, got %d", resp.Code)
}
var body map[string]string
json.Unmarshal(resp.Body.Bytes(), &body)
if body["status"] != "ok" {
t.Errorf("expected ok, got %s", body["status"])
}
}
func TestCreateUser(t *testing.T) {
client := nimbustest.NewTestClient(setupTestApp().Router)
resp := client.Post("/users", []byte(`{"name":"Alice"}`))
if resp.Code != 201 {
t.Fatalf("expected 201, got %d", resp.Code)
}
}