英文:
httptest ResponseRecorder keeps the old value
问题
我有一个需要测试的handlerAuthentication
函数:
func handlerAuthentication(c *gin.Context) {
session := Session.GetSession(c)
var login Login
err := c.BindJSON(&login)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
client, err := initClient(c, login)
fmt.Println("Error: ", err)
if err != nil {
fmt.Println("There's an error!")
c.JSON(http.StatusUnauthorized, gin.H{"error": ErrorWrongLogin})
return
}
err = (*client).Logout(c)
if err != nil {
return
}
session.Set("username", login.Username)
session.Set("password", login.Password)
err = session.Save()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "an error occurred during the save of the session:" + err.Error()})
return
}
c.JSON(http.StatusOK, "Connected")
}
为了测试它,我做了以下工作:
func TestHandlerAuthentication(t *testing.T) {
UrlOdoo = "https://isi.nc"
resp := httptest.NewRecorder()
gin.SetMode(gin.TestMode)
c, r := gin.CreateTestContext(resp)
r.POST("/test", func(c *gin.Context) {
handlerAuthentication(c)
})
ctrl := gomock.NewController(t)
defer ctrl.Finish()
Odoo = OdooRPC{createMockOdooClient}
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)
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) {
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)
resp.Flush()
})
}
}
我面临的问题是,如果我逐个运行测试(valid login
和invalid login
),它们都会通过,但是当我同时运行这两个测试时,第二个测试会失败。
以下是同时执行这两个测试的示例:
=== RUN TestHandlerAuthentication
=== RUN TestHandlerAuthentication/valid_login
Error: <nil> //没有错误,所以resp.Code应该等于200
=== RUN TestHandlerAuthentication/invalid_login
Error: invalid login //有错误,所以resp.Code应该等于401
There's an error!
main_test.go:394:
Error Trace: main_test.go:394
Error: Not equal:
expected: 401
actual : 200
Test: TestHandlerAuthentication/invalid_login
--- FAIL: TestHandlerAuthentication (0.00s)
--- PASS: TestHandlerAuthentication/valid_login (0.00s)
--- FAIL: TestHandlerAuthentication/invalid_login (0.00s)
Expected :401
Actual :200
正如预期的那样,当登录无效时发生错误,但是resp.Code
仍然是200。
如果我先运行invalid login
测试,resp.Code
仍然是401。
这是因为测试是并行执行的,而httptest
的ResponseRecorder
在并行中不起作用吗?
谢谢你的帮助。
英文:
I have a handlerAuthentication
function that I need to test:
func handlerAuthentication(c *gin.Context) {
session := Session.GetSession(c)
var login Login
err := c.BindJSON(&login)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
client, err := initClient(c, login)
fmt.Println("Error: ",err)
if err != nil {
fmt.Println("There's an error !")
c.JSON(http.StatusUnauthorized, gin.H{"error": ErrorWrongLogin})
return
}
err = (*client).Logout(c)
if err != nil {
return
}
session.Set("username", login.Username)
session.Set("password", login.Password)
err = session.Save()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "an error occurred during the save of the session:" + err.Error()})
return
}
c.JSON(http.StatusOK, "Connected")
}
To do so,I made this:
func TestHandlerAuthentication(t *testing.T) {
UrlOdoo = "https://isi.nc"
resp := httptest.NewRecorder()
gin.SetMode(gin.TestMode)
c, r := gin.CreateTestContext(resp)
r.POST("/test", func(c *gin.Context) {
handlerAuthentication(c)
})
ctrl := gomock.NewController(t)
defer ctrl.Finish()
Odoo = OdooRPC{createMockOdooClient}
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)
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) {
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)
resp.Flush()
})
}
}
The problem I'm facing is that if I do the tests one by (valid login
and invalid login
), they all pass, but when I do the two tests at the same time, the second test fails.
Here's an exemple of execution of the two tests at the same time:
=== RUN TestHandlerAuthentication
=== RUN TestHandlerAuthentication/valid_login
Error: <nil> //No error, so resp.Code should be equal to 200
=== RUN TestHandlerAuthentication/invalid_login
Error: invalid login //Error, so resp.Code should be equal to 401
There's an error !
main_test.go:394:
Error Trace: main_test.go:394
Error: Not equal:
expected: 401
actual : 200
Test: TestHandlerAuthentication/invalid_login
--- FAIL: TestHandlerAuthentication (0.00s)
--- PASS: TestHandlerAuthentication/valid_login (0.00s)
--- FAIL: TestHandlerAuthentication/invalid_login (0.00s)
Expected :401
Actual :200
As expected, an error occured when the login is invalid, but the resp.Code is still 200.
And if I do the invalid login
test first, the resp.Code will still be 401.
Is it happening because the tests are parallelized and the httptest ResponseRecorder doesn't work in parallel ?
Thank you for your help.
答案1
得分: 0
谢谢leaf bebop。
我需要为每个测试初始化一个新的httptest.ResponseRecorder
。为此,我将初始化移到了t.Run(name,func(t *testing.T)
函数中:
func TestHandlerAuthentication(t *testing.T) {
UrlOdoo = "https://isi.nc"
ctrl := gomock.NewController(t)
defer ctrl.Finish()
Odoo = OdooRPC{createMockOdooClient}
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)
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) {
resp := httptest.NewRecorder()
gin.SetMode(gin.TestMode)
c, r := gin.CreateTestContext(resp)
r.POST("/test", func(c *gin.Context) {
handlerAuthentication(c)
})
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)
})
}
}
英文:
Thank you leaf bebop
I needed to initialize a new httptest.ResponseRecorder
for each test.
To do so, I move the initialisation to the t.Run(name,func(t *testing.T)
function:
func TestHandlerAuthentication(t *testing.T) {
UrlOdoo = "https://isi.nc"
ctrl := gomock.NewController(t)
defer ctrl.Finish()
Odoo = OdooRPC{createMockOdooClient}
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)
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) {
resp := httptest.NewRecorder()
gin.SetMode(gin.TestMode)
c, r := gin.CreateTestContext(resp)
r.POST("/test", func(c *gin.Context) {
handlerAuthentication(c)
})
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)
})
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论