Testing a multipart form upload endpoint in Echo framework
Asked Answered
R

1

6

I'm using labstack's Echo framework for building APIs in Golang. Now I have a problem that I can't seem to get around when I want to test an endpoint.

I have a handler function like this

func DoStuff(c echo.Context) error {
    businessUnit := strings.ToUpper(c.FormValue("bu"))
    week := c.FormValue("wk")

    file, _ := c.FormFile("file")

    ...
}

The handler works just fine. The problem I have now is writing integration tests for this.

This endpoint accepts a Content-Type: multipart/form-data.

Here's how some of my other handler tests look:

func TestDoStuff(t *testing.T) {

    // Not sure about this part tho
    body := new(bytes.Buffer)
    writer := multipart.NewWriter(body)
    writer.WriteField("bu", "HFL")
    writer.WriteField("wk", "10")
    part, _ := writer.CreateFormFile("file", "file.csv")
    part.Write([]byte(`sample`))


    e := echo.New()
    req := httptest.NewRequest(http.MethodPost, "/endpoint", body)
    req.Header.Add("Content-Type", "multipart/form-data")
    rec := httptest.NewRecorder()
    c := e.NewContext(req, rec)

    if assert.NotPanics(t, func(){ _ = DoStuff(c)}){
        assert.Equal(t, http.StatusOK, rec.Code)
        ... more assertions ...
    }
}

I can't seem to get the form values in the handler. Any help would be greatly appreciated.

Ribbonfish answered 24/1, 2020 at 2:9 Comment(0)
C
10

TLDR

func TestDoStuff(t *testing.T) {
    body := new(bytes.Buffer)
    writer := multipart.NewWriter(body)
    writer.WriteField("bu", "HFL")
    writer.WriteField("wk", "10")
    part, _ := writer.CreateFormFile("file", "file.csv")
    part.Write([]byte(`sample`))
    writer.Close() // <<< important part

    e := echo.New()
    req := httptest.NewRequest(http.MethodPost, "/endpoint", body)
    req.Header.Set("Content-Type", writer.FormDataContentType()) // <<< important part
    rec := httptest.NewRecorder()
    c := e.NewContext(req, rec)
    ...
}

Explanation. When you close multipart.Writer in actually writes boundary id to body (which is very important part!). That id later is written to headers using writer.FormDataContentType().

The thing is when you call FormValue, FormFile, etc. go calls req.ParseMultipartForm() who in turn go and look for boundary id in multipart/form-data header, and then using said id searches for body data.

Crites answered 27/1, 2020 at 16:3 Comment(3)
Thanks a lot, let me test this outRibbonfish
I forgot to close my writer! Thank you so much!Fino
@Ribbonfish please mark this answer as acceptedFootwear

© 2022 - 2024 — McMap. All rights reserved.