优先用httptest.newrequest+newrecorder测单个handler,轻量快速、不占端口;仅当需验证中间件、路由或客户端行为时才用newserver,并注意端口管理与依赖注入。

别用 http.Get 直连本地端口测 handler,90% 的测试根本不需要起服务,也别一上来就写 httptest.NewServer —— 它只在必须走完整网络栈时才该用。
用 httptest.NewRequest + httptest.NewRecorder 测单个 handler
这是最轻、最快、最可控的方式,适合验证路由参数解析、状态码、JSON 序列化、Header 设置等。整个过程不占端口、不启 goroutine、不走网络层。
-
http.NewRequest构造请求时,body为nil表示空体;传 JSON 必须用strings.NewReader(`{}`)并显式设req.Header.Set("Content-Type", "application/json") -
httptest.NewRecorder()返回的*httptest.ResponseRecorder不是真实http.ResponseWriter实现,但兼容所有写入方法,可直接读.Code、.Body.Bytes()、.Header() - 必须显式调用
handler.ServeHTTP(rr, req),漏掉这行等于没执行逻辑 - 常见 panic 来自传
nil给ServeHTTP;常见误判来自忽略 JSON 数字在map[string]interface{}中是float64类型
用 httptest.NewServer 测中间件、路由或客户端行为
当你用 Gin/Echo/http.ServeMux,且中间件(JWT 鉴权、CORS、日志)参与响应流程时,NewRecorder 会完全跳过它们——必须把整个 handler 树丢给 NewServer。
-
NewServer启一个真实 HTTP 服务,返回带随机端口的srv.URL(如"http://127.0.0.1:34212"),客户端代码必须用它,不能硬写"localhost:8080" - 每次调用都绑定新端口,务必
defer srv.Close(),否则测试间端口耗尽、goroutine 泄漏 - 不支持 HTTPS;若需 TLS 测试,得用
httptest.NewUnstartedServer手动配srv.TLS - 若 handler 依赖全局状态(如 DB 连接池、配置变量),测试前需重置或注入 mock,否则状态污染
JSON 响应断言最容易踩的坑
Go 标准库无内置断言,靠手动比对 rec.Code 和 json.Unmarshal(rec.Body.Bytes(), &v),但类型和格式稍不注意就错。
- 状态码必须显式检查,不能只看响应体是否非空
- 用
map[string]interface{}解析时,JSONnumber是float64,bool是bool,null是nil;比如resp["id"] == 123会失败,得写resp["id"] == float64(123) - 结构体固定时,优先定义具体 struct 并用
json.Unmarshal,比泛型 map 更安全、字段名更明确 - 字符串比对(如
strings.Contains(rec.Body.String(), "token"))容易因空格、换行、字段顺序失败;建议用assert.JSONEq(testify)或自己做规范化比较
测 HTTP 客户端时别绕开 http.Client 行为
如果你写的不是 handler,而是调第三方 API 的 client(带重试、超时、重定向、header 透传),那重点不是 mock response,而是验证 client 是否按预期发出了请求。
- 仍用
httptest.NewServer,但在 handler 里检查r.Method、r.URL.Path、r.Header.Get("Authorization")等,确认 client 没发错 - 不要在测试里用
http.DefaultClient,应把 client 作为参数注入,便于替换 transport 或控制超时 - 避免用自定义
RoundTripper拦截请求——实现不全(如忽略req.Context().Done())会导致测试卡死或资源泄漏;NewServer更稳 - 测重定向时,
http.Client默认跟随,要验证跳转链,得关掉CheckRedirect或用srv.URL做跳转目标
真正难的不是怎么写测试,而是判断该用 NewRecorder 还是 NewServer:只要 handler 不依赖中间件、路由树或客户端侧行为,就永远优先选前者;一旦涉及 Header 透传、CORS 头生成、JWT 验证顺序、重定向跳转,就必须切到后者——这个边界模糊点,是多数人反复重构测试的原因。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











