Gin单元测试应使用gin.CreateTestContext配合httptest.NewRequest构造mock请求,避免启动真实服务器;需显式注册中间件、用ShouldBindJSON替代BindJSON、手动设置Query/Header/Cookie/Form等参数。
直接用 gin.CreateTestContext 搭配 httptest.NewRequest 发起请求
Gin 本身不依赖 HTTP 服务器启动就能跑测试,关键在于构造一个带 mock request/response 的上下文。别写 router.Run() 或起真实端口——那不是单元测试,是集成测试,慢且不稳定。
实操要点:
- 用
gin.New()或gin.Default()创建 router 实例,它本身是线程安全的,可复用 - 调用
httptest.NewRequest("GET", "/api/user/123", nil)构造请求,注意方法、路径、body(如需 JSON,用strings.NewReader(`{"name":"a"}`)) - 用
httptest.NewRecorder()创建响应记录器,它实现了http.ResponseWriter - 手动调用
router.ServeHTTP(w, req),跳过监听端口环节
示例片段:
req, _ := http.NewRequest("GET", "/user/1", nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Fatalf("expected status %d, got %d", http.StatusOK, w.Code)
}
测试带中间件的路由时,必须显式注册中间件
Gin 的中间件不会自动生效于测试上下文——router.Use() 是声明式的,但测试中你得确保它被调用。漏掉中间件(比如 JWT 验证、日志、CORS)会导致测试通过但线上报错,或者反过来:测试失败但线上正常。
常见踩坑点:
- 只在 main.go 里调用了
r.Use(authMiddleware),但测试文件里 new 出来的 router 是干净的,没加载任何中间件 - 中间件依赖外部服务(如 Redis、DB),测试时没 mock,导致 panic 或超时
- 使用
gin.TestMode不影响中间件行为,它只关闭了调试日志和一些 panic 捕获
建议做法:把 router 初始化逻辑抽成函数,接受中间件切片,测试时传入 mock 版本: