【问题标题】:Test for handler with file upload使用文件上传测试处理程序
【发布时间】:2023-01-20 17:00:00
【问题描述】:

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

我的意图是创建一个文件并使用 multipart.FileHeader 打开它。

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 方法返回:“打开:没有这样的文件或目录”

【问题讨论】:

标签: go go-testing


【解决方案1】:

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

上传

上传在handlers_test.go 文件中完成。我编写了两个测试来展示如何使用多部分主体创建有效的 HTTP 请求(我假设通信是基于 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 请求中检索并解析 Content-Type 标头
  2. 我们检查上面的值是否以字符串multipart/开头
  3. 如果是这样,我们读取正文的下一部分(也是唯一的)并将其内容写入响应流
  4. 如果不是,我们向 HTTP 客户端返回一个BadRequest错误

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-28
    • 2012-01-18
    • 2011-07-12
    • 2013-06-11
    • 2017-03-28
    • 2010-11-17
    • 1970-01-01
    • 2016-09-23
    相关资源
    最近更新 更多