Go API testing patterns -- httptest setup, table-driven tests with subtests, test helpers, middleware testing, dependency injection with interfaces, database isolation, parallel tests, testify assertions, golden files
98
98%
Does it follow best practices?
Impact
99%
1.06xAverage score across 5 eval scenarios
Passed
No known issues
A team building a Go REST API has added JWT-based authentication middleware. The middleware extracts a Bearer token from the Authorization header, validates it, and injects the user email into the request context. Protected endpoints use this context value to identify the current user.
After a recent refactor, the middleware accidentally started accepting expired tokens. The team wants a test suite that catches this class of bug by testing the middleware in isolation (wrapping a dummy handler) and also testing a protected endpoint through the full middleware chain.
Produce the following files:
middleware_test.go -- tests for the auth middleware in isolationhandlers_test.go -- tests for the protected /api/profile endpoint through the middleware chaintesthelpers_test.go -- shared test helpersThe tests must use httptest from the standard library. Table-driven tests with t.Run subtests are expected for the multiple auth scenarios.
The following files are provided as inputs. Extract them before beginning.
=============== FILE: go.mod =============== module authapi
go 1.23
require github.com/golang-jwt/jwt/v5 v5.2.1
=============== FILE: main.go =============== package main
import ( "context" "encoding/json" "log" "net/http" "strings" "time"
"github.com/golang-jwt/jwt/v5")
var jwtSecret = []byte("test-secret-key-do-not-use-in-production")
type contextKey string
const userEmailKey contextKey = "userEmail"
func main() { mux := setupRoutes() log.Println("Server starting on :8080") log.Fatal(http.ListenAndServe(":8080", mux)) }
func setupRoutes() *http.ServeMux { mux := http.NewServeMux() mux.HandleFunc("GET /api/health", handleHealth) mux.Handle("GET /api/profile", AuthMiddleware(http.HandlerFunc(handleProfile))) mux.HandleFunc("POST /api/login", handleLogin) return mux }
func AuthMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { authHeader := r.Header.Get("Authorization") if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") { writeError(w, http.StatusUnauthorized, "missing or invalid authorization header") return }
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (any, error) {
return jwtSecret, nil
})
if err != nil || !token.Valid {
writeError(w, http.StatusUnauthorized, "invalid token")
return
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
writeError(w, http.StatusUnauthorized, "invalid token claims")
return
}
email, ok := claims["email"].(string)
if !ok {
writeError(w, http.StatusUnauthorized, "missing email in token")
return
}
ctx := context.WithValue(r.Context(), userEmailKey, email)
next.ServeHTTP(w, r.WithContext(ctx))
})}
func handleHealth(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, map[string]any{"status": "ok"}) }
func handleProfile(w http.ResponseWriter, r *http.Request) { email := r.Context().Value(userEmailKey).(string) writeJSON(w, http.StatusOK, map[string]any{ "data": map[string]any{"email": email, "role": "user"}, }) }
func handleLogin(w http.ResponseWriter, r *http.Request) {
var body struct {
Email string json:"email"
Password string json:"password"
}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
writeError(w, http.StatusBadRequest, "invalid JSON")
return
}
if body.Email == "" || body.Password == "" {
writeError(w, http.StatusBadRequest, "email and password required")
return
}
// Simplified: accept any email/password
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"email": body.Email,
"exp": time.Now().Add(time.Hour).Unix(),
})
tokenString, _ := token.SignedString(jwtSecret)
writeJSON(w, http.StatusOK, map[string]any{"access_token": tokenString})
}
func writeJSON(w http.ResponseWriter, status int, data any) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) json.NewEncoder(w).Encode(data) }
func writeError(w http.ResponseWriter, status int, message string) { writeJSON(w, status, map[string]any{"error": map[string]any{"message": message}}) }
func generateTestToken(email string, expiry time.Time) string { token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "email": email, "exp": expiry.Unix(), }) s, _ := token.SignedString(jwtSecret) return s }