我有这个请求处理程序的代码:
func (h *Handlers) UpdateProfile() gin.HandlerFunc {
type request struct {
Username string `json:"username" binding:"required,min=4,max=20"`
Description string `json:"description" binding:"required,max=100"`
}
return func(c *gin.Context) {
var updateRequest request
if err := c.BindJSON(&updateRequest); err != nil {
var validationErrors validator.ValidationErrors
if errors.As(err, &validationErrors) {
validateErrors := base.BindingError(validationErrors)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": validateErrors})
} else {
c.AbortWithError(http.StatusBadRequest, err)
}
return
}
avatar, err := c.FormFile("avatar")
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
"error": "image not contains in request",
})
return
}
log.Print(avatar)
if avatar.Size > 3<<20 { // if avatar size more than 3mb
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
"error": "image is too large",
})
return
}
file, err := avatar.Open()
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
}
session := sessions.Default(c)
id := session.Get("sessionId")
log.Printf("ID type: %T", id)
err = h.userService.UpdateProfile(fmt.Sprintf("%v", id), file, updateRequest.Username, updateRequest.Description)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{})
return
}
c.IndentedJSON(http.StatusNoContent, gin.H{"message": "succesfull update"})
}
}
我有这个处理程序的单元测试:
func TestUser_UpdateProfile(t *testing.T) {
type testCase struct {
name string
image io.Reader
username string
description string
expectedStatusCode int
}
router := gin.Default()
memStore := memstore.NewStore([]byte("secret"))
router.Use(sessions.Sessions("session", memStore))
userGroup := router.Group("user")
repo := user.NewMemory()
service := userService.New(repo)
userHandlers.Register(userGroup, service)
testImage := make([]byte, 100)
rand.Read(testImage)
image := bytes.NewReader(testImage)
testCases := []testCase{
{
name: "Request With Image",
image: image,
username: "bobik",
description: "wanna be sharik",
expectedStatusCode: http.StatusNoContent,
},
{
name: "Request Without Image",
image: nil,
username: "sharik",
description: "wanna be bobik",
expectedStatusCode: http.StatusNoContent,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
imageWriter, err := writer.CreateFormFile("avatar", "test_avatar.jpg")
if err != nil {
t.Fatal(err)
}
if _, err := io.Copy(imageWriter, image); err != nil {
t.Fatal(err)
}
data := map[string]interface{}{
"username": tc.username,
"description": tc.description,
}
jsonData, err := json.Marshal(data)
if err != nil {
t.Fatal(err)
}
jsonWriter, err := writer.CreateFormField("json")
if err != nil {
t.Fatal(err)
}
if _, err := jsonWriter.Write(jsonData); err != nil {
t.Fatal(err)
}
writer.Close()
// Creating request
req := httptest.NewRequest(
http.MethodPost,
"http://localhost:8080/user/account/updateprofile",
body,
)
req.Header.Set("Content-Type", writer.FormDataContentType())
log.Print(req)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, tc.expectedStatusCode, w.Result().StatusCode)
})
}
}
在测试过程中,我遇到以下错误: 错误#01:数字文本中的字符‘-’无效
下面是请求正文(我用log.Print(Req)打印它):
&{POST http://localhost:8080/user/account/updateprofile HTTP/1.1 1 1 map[Content-Type:[multipart/form-data; boundary=30b24345de9d8d83ecbdd146262d86894c45b4f3485e4615553621fd2035]] {--30b24345de9d8d83ecbdd146262d86894c45b4f3485e4615553621fd2035
Content-Disposition: form-data; name="avatar"; filename="test_avatar.jpg"
Content-Type: application/octet-stream
--30b24345de9d8d83ecbdd146262d86894c45b4f3485e4615553621fd2035
Content-Disposition: form-data; name="json"
{"description":"wanna be bobik","username":"sharik"}
--30b24345de9d8d83ecbdd146262d86894c45b4f3485e4615553621fd2035--
} <nil> 414 [] false localhost:8080 map[] map[] <nil> map[] 192.0.2.1:1234 http://localhost:8080/user/account/updateprofile <nil> <nil> <nil> <nil>}
首先,我只将字符串作为json数据,并将其转换为字节.当出现错误时,我使用json.Marshal转换json数据,但它不起作用.我想用c.Bind解析json数据,用c.FormFile解析给定的图像,可以吗?
UPD.我先替换代码以获取头像,然后通过绑定 struct 获取json.现在我有了EOF错误.