Golang如何测试HTTP接口 Go Web接口测试方法

10次阅读

httptest.NewServer 或 httptest.NewRecorder 可模拟 HTTP 生命周期:前者测客户端行为并开真实端口,后者轻量直接调 handler 适合单元测试;需避免传 nil handler 和漏调 server.Close(),并注意依赖隔离、状态码jsON 响应的正确断言。

Golang如何测试HTTP接口 Go Web接口测试方法

net/http/httptest 启动假服务器测接口

不用起真实服务,httptest.NewServerhttptest.NewRecorder 就能模拟完整 HTTP 生命周期。前者适合测试客户端行为(比如你写的 HTTP client 是否正确发请求),后者更轻量,直接调 handler 函数,跳过网络层,适合单元测试。

常见错误是直接传 nil 给 handler 导致 panic;或者忘了在测试末尾调用 server.Close(),导致端口被占、后续测试失败。

  • 路由中间件逻辑 → 用 httptest.NewRecorder + 手动构造 *http.Request
  • 测跨服务调用或重定向行为 → 用 httptest.NewServer,它会开真实端口并返回 *url.URL
  • 注意:若 handler 依赖全局状态(如数据库连接池、配置变量),测试前需重置或注入 mock,否则测试间会污染

如何写可断言的测试用例(含 json状态码

go 标准库不带断言库,得自己比对 recorder.Coderecorder.Body.String(),再用 json.Unmarshal 解析响应体。容易出错的地方是忽略空格、换行、字段顺序(JSON 解析不敏感,但字符串比对敏感)。

示例片段:

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

req, _ := http.NewRequest("GET", "/api/user/123", nil) rec := httptest.NewRecorder() handler.ServeHTTP(rec, req)  if rec.Code != http.StatusOK {     t.Fatalf("expected status %d, got %d", http.StatusOK, rec.Code) } var resp map[string]interface{} if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {     t.Fatal("failed to unmarshal response:", err) } if resp["id"] != float64(123) { // 注意 JSON number 默认是 float64     t.Error("expected id=123") }
  • 状态码必须显式检查,不能只看响应体是否非空
  • JSON 字段值类型要小心:intboolNULLmap[string]Interface{} 中对应不同 Go 类型
  • 结构体固定,优先用具体 Struct + json.Unmarshal,比 map 更安全、易读

测试带中间件的 handler(如 JWT 验证、日志、CORS)

中间件本质是函数套函数:func(http.Handler) http.Handler。测试时要把目标 handler 包进中间件链里,再丢给 httptest —— 否则中间件逻辑完全没跑。

典型坑是忘记传入 context 或依赖未初始化的依赖项(比如中间件里调了 db.QueryRow,但测试时没 mock db)。

  • 验证中间件是否生效:检查响应头(如 rec.Header().Get("X-Content-Type-Options"))、状态码(如未登录返回 401)、或副作用(如日志是否写入 buffer)
  • 若中间件依赖外部服务,用 interface 抽离,并在测试中注入 fake 实现(比如 type TokenValidator interface { Validate(string) (Claims, error) }
  • 避免在测试中用 os.Setenv 改全局环境变量——并发测试会冲突;改用局部配置变量或函数参数传入

怎么测超时、重试、错误响应这些边界情况

标准 http.Client 支持设置 TimeoutTransport,你可以用自定义 RoundTripper 模拟慢响应或连接中断。比如让 transport 在第 2 次请求时才返回,就能测重试逻辑。

更简单的方法是绕过 client,直接调用你的业务函数(比如 FetchUserInfo(ctx, userID)),然后传入带 cancel 的 context.WithTimeout,观察是否提前返回错误。

  • 测试超时:用 context.WithTimeout(context.background(), 1*time.Millisecond),确保 handler 内部用了该 ctx 做 I/O 控制
  • 测试网络错误:自定义 http.RoundTripper 返回 net.ErrClosed 或直接 panic,看上层是否捕获并降级
  • 别依赖 sleep 等待异步完成——用 sync.WaitGroupchannel 显式同步

测试最难的不是写断言,而是隔离依赖和控制执行流。尤其是当 handler 里混着 DB 查询、HTTP 调用、时间操作时,每个都得有可替换、可预测的替身。

text=ZqhQzanResources