golangでテキストフィールドとファイルフィールドを持つmultipartなRequestBodyをつくる

Jomonのテストで少し困ったのでメモ。

Postmanでいう以下の画像の、textのフィールドとfileのフィールドどちらも持つようなPOSTをgolangで生成したい場合、multipart.WriteFieldmultipart.CreatePartを使います。

f:id:cskd8:20210902163300p:plain

画像ファイルなどを送りたい場合、mimetypeはimage/jpegなどにしてあげたいですが、multipart.CreateFormFileでは固定でapplication/octet-streamになってしまうようなので注意が必要です。

package main

import (
    "encoding/base64"
    "log"
    "mime/multipart"
    "io"
    "net/textproto"
    "net/http"
    "net/http/httptest"
    "testing"

    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/require"
)

var testJpeg = `base64エンコードした画像ファイル`

func TestPostFile(t *testing.T) {
    router := NewRouter()

    pr, pw := io.Pipe()
    writer := multipart.NewWriter(pw)
    go func() {
        defer writer.Close()
        writer.WriteField("name", "test")
        part := make(textproto.MIMEHeader)
        part.Set("Content-Type", "image/jpeg")
        part.Set("Content-Disposition", `form-data; name="file"; filename="test.jpg"`)
        wp, err := writer.CreatePart(part)
        require.NoError(t, err)
        file, err := base64.RawStdEncoding.DecodeString(testJpeg)
        require.NoError(t, err)
        _, err = wp.Write(file)
        require.NoError(t, err)
    }()

    req := httptest.NewRequest("POST", "/api/files", pr)
    req.Header.Set("Content-Type", writer.FormDataContentType())
    rec := httptest.NewRecorder()
    router.ServeHTTP(rec, req)
    assert.Equal(t, http.StatusOK, rec.Code)
}

References