如何在Golang中测试HTTP Handler的响应 Go语言httptest.ResponseRecorder使用

1次阅读

httptest.NewRecorder 是模拟 ResponseWriter 的工具,用于捕获 handler 输出而非发起请求;需传给符合 func(http.ResponseWriter, *http.Request) 签名的 handler,并配合 httptest.NewRequest 构造含 body、header 和 query 的真实请求;status code 依赖 handler 显式调用 WriteHeader,否则 rr.Code 为 0;可测试中间件和路由,但需确保调用链完整。

如何在 Golang 中测试 HTTP Handler 的响应 Go 语言 httptest.ResponseRecorder 使用

怎么用 httptest.NewRecorder 捕获 handler 输出

它不是用来“发起请求”的,而是模拟一个响应写入目标——ResponseWriter 的替代品。你把它传给 handler,handler 调用 w.WriteHeader()w.Write() 时,数据就存进 ResponseRecorder 里了,不走网络。

常见错误是直接拿 ResponseRecorder*http.Response 用(比如想读 .Body),但它没有 Body 字段;得用 .Body.Bytes().Body.String() 取内容。

  • 必须在调用 handler 前初始化:rr := httptest.NewRecorder()
  • handler 签名必须是 func(http.ResponseWriter, *http.Request),别漏指针
  • 记得传真实构造的 *http.Request,用 httptest.NewRequest() 最稳,别手写 nil 或空结构体

httptest.NewRequest 怎么构造带 body 和 header 的测试请求

很多 handler 依赖 Content-TypeAuthorization 或 JSON body,光用 http.MethodGet 和路径不够。

httptest.NewRequest 第三个参数支持 io.Reader,所以 JSON 字符串要转成 strings.NewReader(jsonStr);如果 body 为空,传 nil 即可,但别传空字符串(会变成长度为 0 的 body,Content-Length: 0)。

立即学习 go 语言免费学习笔记(深入)”;

  • JSON 请求示例:req := httptest.NewRequest("POST", "/api/user", strings.NewReader(`{"name":"a"}`))
  • 设 header:req.Header.Set("Content-Type", "application/json"),注意大小写不敏感但值要准确
  • URL 查询参数用 req.URL.RawQuery = "id=123",别改 req.URL.Path

为什么测试里 status code 总是 200 或 0

status code 是 handler 主动调用 w.WriteHeader(code) 写进去的。如果 handler 没调,rr.Code 默认是 0;如果 handler panic 或提前 return 没写状态码,Go http 包会在最后隐式写 200——但 ResponseRecorder 不会帮你补这个逻辑,它只记录你真正写的东西。

  • 检查 handler 是否遗漏 w.WriteHeader(),尤其在 error 分支里
  • 不要依赖“没写就是 200”,测试中显式断言 assert.Equal(t, 400, rr.Code)
  • 如果 handler 用了第三方库(如 Gin、Echo),它们可能封装了 WriteHeader,但 ResponseRecorder 仍能捕获,没问题

测试中间件或路由时,ResponseRecorder 还够用吗

够用,但要注意调用链顺序。如果你测的是完整路由(比如用 http.ServeMuxgin.Engine),那就把整个 handler 链丢给 rr;如果只测单个中间件函数,它通常接收 http.Handler 并返回新 http.Handler,那你得手动构造下一层 handler 并传给它。

  • 测 Gin handler:router.ServeHTTP(rr, req),不用拆
  • 测自定义中间件:next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}),再套 myMiddleware(next)
  • 注意中间件可能修改 ResponseWriter(如加 header),这些修改都会反映在 rr

最易被忽略的是:handler 里调用 log.Printfmt.Println 不影响 ResponseRecorder,但若用了 panic 且没 recover,测试会直接失败——这时候 rr 里什么都没有,Code 是 0,Body 是空。

text=ZqhQzanResources