Golang httptest POST请求:加JSON头遇运行时错误,不加无法读取负载
登录路由测试问题排查
问题描述
我在给一个仅需2个必填参数的简易登录路由写测试,添加application/json请求头发起POST请求时会返回运行时错误;移除该请求头后错误消失,但又无法读取请求负载。
测试代码
package main import ( "fmt" "net/http" "net/http/httptest" "strings" "testing" "github.com/gigilaw/ultihats/routes" "github.com/stretchr/testify/assert" ) func TestRegisterEmailRoute(t *testing.T) { router := routes.ApiRoutes() payload := strings.NewReader(`{ "email":"abc@gmail.com", "password": "abc12345" }`, ) w := httptest.NewRecorder() req, err := http.NewRequest("POST", "/login", payload) if err != nil { fmt.Println(err) } req.Header.Add("Content-Type", "application/json") router.ServeHTTP(w, req) assert.Equal(t, 200, w.Code) }
报错信息
2022/11/02 18:32:35 [Recovery] 2022/11/02 - 18:32:35 panic recovered: POST /login HTTP/1.1 Content-Type: application/json runtime error: invalid memory address or nil pointer dereference /usr/local/go/src/runtime/panic.go:260 (0x104f8d5) panicmem: panic(memoryError) /usr/local/go/src/runtime/signal_unix.go:835 (0x104f8a5) sigpanic: panicmem() /Users/gigilaw/Desktop/go/pkg/mod/gorm.io/gorm@v1.24.0/gorm.go:372 (0x1698f18) (*DB).getInstance: if db.clone > 0 { /Users/gigilaw/Desktop/go/pkg/mod/gorm.io/gorm@v1.24.0/chainable_api.go:279 (0x1691995) (*DB).Preload: tx = db.getInstance() /Users/gigilaw/Desktop/go/src/github.com/gigilaw/ultihats/api/controllers/authController.go:64 (0x16d894e) UserLogin: initializers.DB.Preload("DiscSkills").First(&user, "email = ?", login.Email) /Users/gigilaw/Desktop/go/pkg/mod/github.com/gin-gonic/gin@v1.8.1/context.go:173 (0x1538181) (*Context).Next: c.handlers[c.index](c) /Users/gigilaw/Desktop/go/pkg/mod/github.com/gin-gonic/gin@v1.8.1/recovery.go:101 (0x153816c) CustomRecoveryWithWriter.func1: c.Next() /Users/gigilaw/Desktop/go/pkg/mod/github.com/gin-gonic/gin@v1.8.1/context.go:173 (0x1537286) (*Context).Next: c.handlers[c.index](c) /Users/gigilaw/Desktop/go/pkg/mod/github.com/gin-gonic/gin@v1.8.1/logger.go:240 (0x1537269) LoggerWithConfig.func1: c.Next() /Users/gigilaw/Desktop/go/pkg/mod/github.com/gin-gonic/gin@v1.8.1/context.go:173 (0x1536350) (*Context).Next: c.handlers[c.index](c) /Users/gigilaw/Desktop/go/pkg/mod/github.com/gin-gonic/gin@v1.8.1/gin.go:616 (0x1535fb8) (*Engine).handleHTTPRequest: c.Next() /Users/gigilaw/Desktop/go/pkg/mod/github.com/gin-gonic/gin@v1.8.1/gin.go:572 (0x1535afc) (*Engine).ServeHTTP: engine.handleHTTPRequest(c) /Users/gigilaw/Desktop/go/src/github.com/gigilaw/ultihats/api/tests/userTest_test.go:31 (0x171d946) TestRegisterEmailRoute: router.ServeHTTP(w, req) /usr/local/go/src/testing/testing.go:1446 (0x111d70a) tRunner: fn(t) /usr/local/go/src/runtime/asm_amd64.s:1594 (0x106db80) goexit: BYTE $0x90 // NOP
问题原因与解决办法
从报错栈能直接定位问题:panic出现在authController.go的initializers.DB.Preload("DiscSkills").First(...)行,说明**initializers.DB是nil指针**——你的测试代码没有初始化数据库连接实例。
- 解决核心问题:在测试函数创建路由之前,先调用数据库初始化逻辑,和业务服务启动时的流程一致。比如添加
initializers.InitDB()(根据你的项目实际初始化函数调整),确保initializers.DB被正确赋值为GORM的DB实例。 - 可选优化:如果不想依赖真实数据库,可以用内存数据库(如SQLite的内存模式)或者Mock库模拟GORM的DB实例,让测试更轻量化,不依赖外部服务。
- 关于有无请求头的差异:去掉
Content-Type: application/json后,Gin不会自动解析JSON请求体,登录逻辑可能因为没获取到参数提前返回,没走到数据库查询的代码分支,所以没触发nil指针panic,但这只是规避了错误,不是解决方法。
内容的提问来源于stack exchange,提问作者Gigi Law
相关产品推荐
相关产品推荐

