httptest.newserver 用于启动临时 http 服务测试完整请求链路(如调用第三方 api),需用 server.url、调用 server.close();httptest.newrecorder 则零网络模拟响应,配合 http.servehttp 直接测试 handler 函数。

怎么用 httptest.NewServer 测试带外部依赖的 Handler
直接启动真实服务再测,容易被网络、端口占用、超时干扰;httptest.NewServer 启一个临时 HTTP 服务,适合测完整请求链路(比如 Handler 里调了 http.Client 请求第三方 API)。但注意:它会监听真实端口,若 Handler 内部又发起请求到 localhost:xxx,可能意外打到自己身上。
- 只在需要模拟“真实服务间调用”时用,比如测中间件转发、OAuth 回调流程
- 启动后记得调用
server.Close(),否则测试进程可能卡住 - 它的
URL是动态分配的,别硬编码"http://localhost:8080",要用server.URL - 如果 Handler 里用了自定义
http.Transport(比如禁用 TLS 验证),NewServer返回的 HTTPS 地址会失败——它默认不配 TLS,得手动关校验或改用 HTTP
怎么用 httptest.NewRecorder 测纯 Handler 函数
90% 的接口逻辑测试其实不需要真起服务。httptest.NewRecorder 模拟响应写入,配合 http.ServeHTTP 直接驱动 Handler 执行,零端口、零网络、秒级完成。
- Handler 类型是
func(http.ResponseWriter, *http.Request),直接传给http.ServeHTTP(recorder, req) -
recorder.Body.String()拿响应体,recorder.Code拿状态码,recorder.Header()拿头信息 - 构造
*http.Request别用http.NewRequest硬写 URL 路径——如果 Handler 依赖r.URL.Path或r.URL.Query(),得用url.Parse显式设好Request.URL - POST/PUT 带 JSON?用
strings.NewReader(jsonData)当 body,并设Content-Type: application/json
为什么 http.HandlerFunc 包裹后测试更稳
有些 Handler 是方法(如 myStruct.ServeHTTP),有些是闭包(如 func(w, r) { ... }),类型不统一。Go 的 http.Handler 接口要求实现 ServeHTTP 方法,而 http.HandlerFunc 是个类型转换器,把函数转成接口,确保测试时调用路径一致。
- 即使你写的是普通函数,也建议显式转成
http.HandlerFunc(handlerFunc)再传给http.ServeHTTP - 避免因类型推导差异导致测试通过但线上 panic(比如误把
func() error当 Handler) - 如果 Handler 依赖结构体字段(如 DB 连接),测试前必须初始化该结构体实例,不能只传函数名
常见错误:404 / 405 / 空响应体
不是代码没跑,是测试环境和运行时环境不一致。
-
404:Handler 注册路径和测试请求路径不匹配,比如路由用"/api/v1/users",但测试发的是"/users";检查r.URL.Path是否被中间件修改过 -
405 Method Not Allowed:Handler 没处理对应 method,比如只写了if r.Method == "GET"却没else分支,也没设w.WriteHeader(405) - 空响应体:忘了调
json.NewEncoder(w).Encode(data)或w.Write([]byte(...));或者defer关闭了 body writer(比如日志中间件提前读了r.Body导致后续读不到) - 测试中用
t.Parallel()?小心全局变量或共享的http.ServeMux实例被并发污染
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











