端到端测试必须用 httptest.server 启动真实 http 服务,走通 tcp 层、路由、中间件等全链路;禁用 httptest.newrequest+recorder 伪测试;客户端需独立 http.client;db 用临时 sqlite 或 postgresql 库;断言须覆盖状态码、headers、body 结构。

用 httptest.Server 启动真实 HTTP 服务,别 mock handler
端到端测试的核心是走通真实请求链路,不是测单个函数逻辑。Golang 的 httptest.Server 能起一个带完整 TCP 层的真实服务器,路由、中间件、TLS(可配)、超时、连接复用等行为和生产一致。httptest.NewServer 返回的地址可直接喂给客户端(比如 http.Client),不依赖任何 mock 框架。
常见错误是只用 httptest.NewRequest + httptest.NewRecorder 做“伪端到端”——这其实只是单元测试,跳过了 net/http 的 ServeHTTP 入口、连接管理、header 解析、body stream 处理等关键路径。
- 必须用
srv := httptest.NewServer(http.HandlerFunc(yourHandler))或srv := httptest.NewServer(yourMux) - 测试完记得调
srv.Close(),否则 goroutine 和端口会泄漏 - 如果 handler 依赖外部服务(如 DB、Redis),它们仍需 mock 或用 testcontainers;但 HTTP 层本身要真跑起来
测试中访问真实数据库,用 testdb 或临时 sqlite 文件
集成测试里 DB 不该被跳过。用内存 SQLite(sqlite3.Open("file::memory:?cache=shared"))或 PostgreSQL 的 CREATE DATABASE test_db_name WITH TEMPLATE template0 方式建临时库,比 mock SQL driver 更可靠——能暴露事务隔离级别、外键约束、JSON 字段解析、time.Time 时区处理等真实问题。
容易踩的坑是复用全局 DB 连接池:测试并发执行时会互相干扰。每个测试应创建独立连接池,或至少在 func TestXxx(t *testing.T) 开头加 t.Parallel() 并确保 DB 实例不共享。
- SQLite 内存模式注意加
?cache=shared,否则多个连接看不到彼此的事务变更 - PostgreSQL 推荐用
pgxpool.Connect(context, "postgres://...?dbname=template1")然后执行CREATE DATABASE+ 新 pool 连接新库 - 避免在
init()或包变量里初始化 DB,它会让测试无法 clean state
用 http.Client 发起真实请求,别用 http.DefaultClient
http.DefaultClient 是全局变量,测试中修改它的 Timeout 或 Transport 会影响其他测试;更危险的是,它默认启用 HTTP/2 和连接复用,在并发测试中可能复用已关闭的连接,导致 connection refused 或 i/o timeout 错误。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
正确做法是每个测试构造自己的 client:
client := &http.Client{
Timeout: 5 * time.Second,
Transport: &http.Transport{
// 可选:禁用 keep-alive 避免连接残留
DisableKeepAlives: true,
},
}
- 显式设
Timeout,防止测试卡死 - 需要验证重试逻辑?自己实现
RoundTripper包一层,不要动DefaultClient - 如果 API 要求 bearer token,用
req.Header.Set("Authorization", "Bearer xxx"),别靠中间件自动注入——那会掩盖鉴权流程是否真走通
断言响应时,检查状态码、headers、body 结构三者缺一不可
只校验 JSON body 字段值是最弱的断言。E2E 测试必须确认整个 HTTP 协议层行为符合预期:比如 401 是否带 WWW-Authenticate header,201 是否含 Location,gzip 压缩是否生效(Content-Encoding: gzip),甚至 CORS header 是否齐全。
常见疏漏是用 bytes.Contains(resp.Body, []byte("success")) 这类模糊匹配,一旦返回体含日志、调试信息或 HTML 模板碎片就误报。
- 先断言
resp.StatusCode == http.StatusCreated,再读 body - 用
json.Unmarshal解析 body 后,对结构体字段做精确比较(比如assert.Equal(t, "user-123", u.ID)) - 检查关键 header:
assert.Equal(t, "application/json", resp.Header.Get("Content-Type"))
真实链路越长,中间某个环节悄悄改了 header 或 status code 的概率越高。这些细节不覆盖,上线后网关或前端就会出问题。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










