测试文件上传的处理程序



我正试图为接收文件的处理程序编写测试。作为其中的一部分,我正试图配置我的上下文,以便处理程序可以使用它。

我的意图是创建一个文件并使用multipart。

f, err := os.CreateTemp("", "upload-test")
require.NoError(t, err)
_, err = f.Write([]byte("1234"))
require.NoError(t, err)
err = f.Close()
require.NoError(t, err)
fileHeader := &multipart.FileHeader{
Filename: f.Name(),
Size:     4,
}
open, err := fileHeader.Open()
require.NoError(t, err)

但是Open方法返回:"open: no such file or directory">

更新:

我的端点接收到下面的结构体

type UploadDatabaseRequest struct {
Group    string                `form:"group" binding:"required"`
Database *multipart.FileHeader `form:"database" binding:"required"`
}

根据Ivan的回答,我试着用multipart.NewReader阅读请求,这样我就可以得到一个*multipart.FileHeader。然而,下面的代码导致了"意外的eof";从呼叫到multipartReader.ReadForm(100000000)

contentType := multipartWriter.FormDataContentType()
_, params, err := mime.ParseMediaType(contentType)
assert.NoError(t, err)
multipartReader := multipart.NewReader(bytes.NewReader(buf.Bytes()), params["boundary"])
form, err := multipartReader.ReadForm(100000000)
require.NoError(t, err)
fileHeader := form.File["file"][0]
uploadRequest := &UploadDatabaseRequest{
Group:    groupName,
Database: fileHeader,
}

我创建了一个示例来演示它应该如何工作。首先,让我展示代码,然后,我将带您浏览所有相关部分。

上传在handlers_test.go文件中完成。我编写了两个测试来展示如何创建具有多部分主体的有效HTTP Request(我假设通信基于HTTP)。您可以在这里找到代码:

package multipart
import (
"bytes"
"io"
"mime/multipart"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestHandleFile(t *testing.T) {
t.Run("MultipartRequest", func(t *testing.T) {
// instantiate multipart request
var buf bytes.Buffer
multipartWriter := multipart.NewWriter(&buf)
defer multipartWriter.Close()
// add form field
filePart, _ := multipartWriter.CreateFormFile("file", "file.txt")
filePart.Write([]byte("Hello, World!"))
r := httptest.NewRequest(http.MethodPost, "/file", &buf)
w := httptest.NewRecorder()
r.Header.Set("Content-Type", multipartWriter.FormDataContentType())
HandleFile(w, r)
data, _ := io.ReadAll(w.Result().Body)
assert.Equal(t, http.StatusOK, w.Result().StatusCode)
assert.Equal(t, []byte("Hello, World!"), data)
})
t.Run("PlainRequest", func(t *testing.T) {
r := httptest.NewRequest(http.MethodPost, "/file", nil)
w := httptest.NewRecorder()
HandleFile(w, r)
assert.Equal(t, http.StatusBadRequest, w.Result().StatusCode)
})
}

我们可以关注子测试MultipartRequest。首先,它实例化了一个多部分主体,该主体稍后将用作我们将要发送的HTTP请求的请求有效负载。然后,我们创建一个文件部件并将虚拟内容写入其中。在发送请求之前,我们必须查看用于解析内容的Content-Type报头。测试的其余部分应该非常简单。

读取(或解析)由HTTP服务器完成。所涉及的文件是handlers.go文件:

package multipart
import (
"io"
"mime"
"mime/multipart"
"net/http"
"strings"
)
func HandleFile(w http.ResponseWriter, r *http.Request) {
mediaType, params, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
if strings.HasPrefix(mediaType, "multipart/") {
multipartReader := multipart.NewReader(r.Body, params["boundary"])
filePart, _ := multipartReader.NextPart()
// pay attention here when you read large file
data, _ := io.ReadAll(filePart)
w.Write(data)
return
}
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("request is not multipart"))
}

在这里,相关步骤可以总结为以下列表:

  1. 我们从HTTP请求
  2. 中检索并解析Content-Type报头我们检查上述值是否以字符串multipart/开头
  3. 如果是,我们读取body的下一部分(也是唯一的一部分),并将其内容写入响应流
  4. 如果没有,我们返回一个BadRequest错误到HTTP客户端

在代码中,我添加了一些注释来解释一些值得注意的微妙部分。此外,我通过不处理任何可能发生的错误来简化代码库。
希望能帮助你解决问题,让我知道!

最新更新