Files
zhuangang/topics/backend/gin/examples/unified-api/api_test.go
T

69 lines
2.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package unifiedapi
import (
"encoding/json"
"io"
"log/slog"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/gin-gonic/gin"
)
func do(t *testing.T, r http.Handler, method, path, body string, hdr map[string]string) (int, Body, http.Header) {
t.Helper()
req := httptest.NewRequest(method, path, strings.NewReader(body))
req.Header.Set("Content-Type", "application/json")
for k, v := range hdr {
req.Header.Set(k, v)
}
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
var b Body
if err := json.Unmarshal(w.Body.Bytes(), &b); err != nil {
t.Fatalf("响应不是统一格式:%s", w.Body.String())
}
return w.Code, b, w.Header()
}
func TestUnifiedResponses(t *testing.T) {
gin.SetMode(gin.TestMode)
r := New(slog.New(slog.NewTextHandler(io.Discard, nil)))
cases := []struct {
name, method, path, body string
status, code int
msgContains string
}{
{"创建成功", "POST", "/api/tasks", `{"title":"写周报","priority":"high"}`, 201, 0, "ok"},
{"必填校验", "POST", "/api/tasks", `{"title":""}`, 400, 40000, "title 不能为空"},
{"枚举校验", "POST", "/api/tasks", `{"title":"a","priority":"urgent"}`, 400, 40000, "priority 只能是 low normal high 之一"},
{"JSON 格式错误", "POST", "/api/tasks", `{"title":`, 400, 40000, "请求体格式错误"},
{"查询存在", "GET", "/api/tasks/1", "", 200, 0, "ok"},
{"查询不存在", "GET", "/api/tasks/999", "", 404, 40400, "资源不存在"},
{"panic 兜底", "GET", "/api/boom", "", 500, 50000, "服务器开小差"},
{"内部错误不泄漏细节", "GET", "/api/db-error", "", 500, 50000, "服务器开小差"},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
status, b, h := do(t, r, c.method, c.path, c.body, nil)
if status != c.status || b.Code != c.code || !strings.Contains(b.Message, c.msgContains) {
t.Fatalf("got %d %+v", status, b)
}
if b.RequestID == "" || h.Get("X-Request-ID") != b.RequestID {
t.Fatalf("缺少请求 ID:%+v", b)
}
if strings.Contains(b.Message, "secret") || strings.Contains(b.Message, "relation") {
t.Fatal("内部错误细节泄漏给了用户")
}
})
}
_, b, _ := do(t, r, "GET", "/api/tasks/1", "", map[string]string{"X-Request-ID": "trace-123"})
if b.RequestID != "trace-123" {
t.Fatalf("应沿用客户端的请求 ID,得到 %q", b.RequestID)
}
}