Gin接口测试时httptest ResponseRecorder保留旧值导致单测失败
你的问题和测试并行化无关,核心原因是多个子测试复用了同一个httptest.ResponseRecorder实例,且错误使用了Flush方法重置状态。
具体原因
httptest.ResponseRecorder的Flush()方法仅负责清空内部缓冲的响应体,不会重置已经记录的状态码、响应头数据,前一个测试用例写入的状态码会一直保留到后一个用例中,才会出现后一个用例逻辑走通但状态码还是前一个值的现象。- 此外你将gin路由上下文、mock实例、全局变量赋值都定义在了子测试外层,多个用例共用这些实例也存在状态污染的风险,比如全局的
client、session如果被某个用例修改,就会影响后续用例执行。
修复方案
将每个子测试需要独立的资源全部移到子测试内部初始化,不要跨用例复用:
func TestHandlerAuthentication(t *testing.T) { UrlOdoo = "https://isi.nc" gin.SetMode(gin.TestMode) ctrl := gomock.NewController(t) defer ctrl.Finish() // 通用mock规则可以放在外层 client = mock_odoorpc.NewMockOdooClient(ctrl) client.EXPECT().Authenticate(gomock.Any(), gomock.Any(), invalidUsername, invalidPassword).AnyTimes().Return(fmt.Errorf("invalid login")) client.EXPECT().Authenticate(gomock.Any(), gomock.Any(), validUsername, validPassword).AnyTimes().Return(nil) client.EXPECT().Logout(gomock.Any()).AnyTimes().Return(nil) session = mock_session.NewMockSession(ctrl) Session = SessionGetter{createMockSession} session.EXPECT().Set("username", validUsername).AnyTimes().Return() session.EXPECT().Set("password", validPassword).AnyTimes().Return() session.EXPECT().Save().AnyTimes().Return(nil) Odoo = OdooRPC{createMockOdooClient} for name, test := range map[string]struct { input Login want int }{ "valid login": { input: Login{ Username: validUsername, Password: validPassword, }, want: 200, }, "invalid login": { input: Login{ Username: invalidUsername, Password: invalidPassword, }, want: 401, }, } { t.Run(name, func(t *testing.T) { // 每个子测试单独创建独立的响应记录器、gin上下文和路由 resp := httptest.NewRecorder() c, r := gin.CreateTestContext(resp) r.POST("/test", handlerAuthentication) body, _ := json.Marshal(test.input) c.Request, _ = http.NewRequest(http.MethodPost, "/test", strings.NewReader(string(body))) r.ServeHTTP(resp, c.Request) assert.Equal(t, test.want, resp.Code) }) } }
补充说明
如果确实需要复用ResponseRecorder,不要用Flush,应该每次用例执行前手动重置所有状态:
resp.Code = http.StatusOK resp.HeaderMap = http.Header{} resp.Body = &bytes.Buffer{} resp.Flushed = false
更推荐每个子测试单独创建实例,避免遗漏重置项导致的隐藏问题。
内容的提问来源于stack exchange,提问作者Couldosh
相关产品推荐
相关产品推荐

