这是一个非常有趣的问题。我可以看到您的团队关心通过测试代码来最大程度地减少可能的错误。这是许多开发人员经常忘记的一个方面。
没有看过您的代码,很难为您的案例提出 100% 正确的答案。
我假设我的示例将用作编写您自己的测试的指南,或者在最好的情况下优化我建议的示例
我使用gin gonic 作为我的项目的 HTTP Web 框架,我编写了一个方法 Authenticate,它被称为每个受保护端点的中间件。然后为了测试我只通过gin.Default ()方法创建了一个http服务器
// Authenticate auth an endpoint
func Authenticate() gin.HandlerFunc {
return func(c *gin.Context) {
var someErr errors.BukyError
someErr.SetUnauthorized()
// Fetch token from the headers
requiredToken := c.GetHeader(constants.AuthorizationHeader)
if len(requiredToken) == 0 {
c.AbortWithStatusJSON(someErr.HttpErrorCode, someErr.JSON())
return
}
splittedToken := strings.SplitN(requiredToken, " ", 2)
if len(splittedToken) != 2 || strings.ToLower(splittedToken[0]) != "bearer" {
primErr := fmt.Errorf("wrong bearer token format on Authorization Header")
someErr.PrimitiveErr = &primErr
c.AbortWithStatusJSON(someErr.HttpErrorCode, someErr.JSON())
return
}
// Get email from encoded token
jwtToken, claims, err := helpers.DecodeJWT(splittedToken[1], false)
if err != nil {
someErr.PrimitiveErr = &err
c.AbortWithStatusJSON(someErr.HttpErrorCode, someErr.JSON())
return
}
if _, err := helpers.VerifyObjectIDs(claims.Subject); !err.IsNilError() {
c.AbortWithStatusJSON(someErr.HttpErrorCode, someErr.JSON())
return
}
// Set the User variable so that we can easily retrieve from other middlewares
// c.Set("User", result)
c.Set(constants.ReqBukyJWTKey, jwtToken)
c.Set(constants.ReqBukyClaimsKey, claims)
// Call the next middlware
c.Next()
}
}
然后我像下面这样测试
func TestAuthenticate(t *testing.T) {
userID := primitive.NewObjectID().Hex()
email := "email@email.com"
firstName := "My Name"
lastName := "My Lastname"
scopes := []string{"im_scope"}
statusOK := "statusOK"
someProtectedPath := constants.UsersPath + "/" + userID
engine := gin.Default()
engine.GET(someProtectedPath, Authenticate(), func(c *gin.Context) {
c.String(http.StatusOK, statusOK)
})
t.Run("NoTokenHeader", func(t *testing.T) {
t.Run("UnsetHeader", func(t *testing.T) {
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", someProtectedPath, nil)
engine.ServeHTTP(w, req)
assert.Equal(t, http.StatusUnauthorized, w.Code)
})
t.Run("EmptyHeader", func(t *testing.T) {
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", someProtectedPath, nil)
req.Header.Set(constants.AuthorizationHeader, "")
engine.ServeHTTP(w, req)
assert.Equal(t, http.StatusUnauthorized, w.Code)
})
})
t.Run("TokenWithBadFormat", func(t *testing.T) {
t.Run("1", func(t *testing.T) {
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", someProtectedPath, nil)
badFormatedToken := "hola.hola"
req.Header.Set(constants.AuthorizationHeader, fmt.Sprintf("Bearer %s", badFormatedToken))
engine.ServeHTTP(w, req)
assert.Equal(t, http.StatusUnauthorized, w.Code)
})
t.Run("2", func(t *testing.T) {
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", someProtectedPath, nil)
badFormatedToken := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ."
req.Header.Set(constants.AuthorizationHeader, fmt.Sprintf("Bearer %s", badFormatedToken))
engine.ServeHTTP(w, req)
assert.Equal(t, http.StatusUnauthorized, w.Code)
})
t.Run("3", func(t *testing.T) {
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", someProtectedPath, nil)
badFormatedToken := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.hola.hola.hola"
req.Header.Set(constants.AuthorizationHeader, fmt.Sprintf("Bearere %s", badFormatedToken))
engine.ServeHTTP(w, req)
assert.Equal(t, http.StatusUnauthorized, w.Code)
})
})
t.Run("ExpiredToken", func(t *testing.T) {
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", someProtectedPath, nil)
expirationTime := time.Second
expiredToken, _, err := helpers.GenerateAccessJWT(userID, email, firstName, lastName, scopes, expirationTime)
time.Sleep(expirationTime * 2)
req.Header.Set(constants.AuthorizationHeader, fmt.Sprintf("Bearer %s", expiredToken))
engine.ServeHTTP(w, req)
assert.Equal(t, http.StatusUnauthorized, w.Code)
assert.Nil(t, err)
})
t.Run("ValidToken", func(t *testing.T) {
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", someProtectedPath, nil)
validToken, _, err := helpers.GenerateAccessJWT(userID, email, firstName, lastName, scopes)
req.Header.Set(constants.AuthorizationHeader, fmt.Sprintf("Bearer %s", validToken))
engine.ServeHTTP(w, req)
assert.Nil(t, err)
assert.Equal(t, http.StatusOK, w.Code)
})
}