You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何构造含multipart/formdata的HTTP请求测试文件上传接口?

How to construct a valid multipart/form-data http.Request to test a Go file-upload handler?

The Scenario

You have a Go HTTP handler that accepts POST requests with multipart/form-data to receive and store files:

func DownloadFiles(w http.ResponseWriter, r *http.Request) {
	r.ParseMultipartForm(2097152) //2MB
	files := r.MultipartForm.File["documents"] //files of type []*multipart.FileHeader
	for _, handler := range files { //handler of type *multipart.FileHeader
		file, err := handler.Open() //file of type multipart.File
		... //Do something with files
	}
	w.WriteHeader(http.StatusOK)
}

You need to create a valid http.Request to test this handler.


Solution: Build the Multipart Request Programmatically

Got it, let's walk through how to build a valid request to test your handler. We'll use Go's built-in mime/multipart package to construct the form data, and leverage httptest utilities to avoid spinning up a real server. Here's a complete, test-ready implementation:

import (
	"bytes"
	"io"
	"mime/multipart"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"
)

func TestDownloadFiles(t *testing.T) {
	// 1. Set up a buffer to hold our multipart form content
	var formBuffer bytes.Buffer
	multipartWriter := multipart.NewWriter(&formBuffer)

	// 2. Add files to the form — make sure the field name matches "documents" from your handler
	// Example 1: Add a local file from disk
	localFile, err := os.Open("test-document.txt")
	if err != nil {
		t.Fatalf("Failed to open test file: %v", err)
	}
	defer localFile.Close()

	// Create the form field for the file; the second arg is the filename sent in the request
	fileField, err := multipartWriter.CreateFormFile("documents", "test-document.txt")
	if err != nil {
		t.Fatalf("Failed to create form file field: %v", err)
	}
	// Copy the local file's content into the form field
	_, err = io.Copy(fileField, localFile)
	if err != nil {
		t.Fatalf("Failed to write file content to form: %v", err)
	}

	// Example 2: Add an in-memory file (no disk read needed)
	inMemFileField, err := multipartWriter.CreateFormFile("documents", "in-memo-note.txt")
	if err != nil {
		t.Fatalf("Failed to create in-memory form field: %v", err)
	}
	_, err = io.WriteString(inMemFileField, "This is the content of an in-memory text file for testing")
	if err != nil {
		t.Fatalf("Failed to write in-memory content: %v", err)
	}

	// 3. Close the multipart writer — this writes the final boundary to the form data (critical!)
	err = multipartWriter.Close()
	if err != nil {
		t.Fatalf("Failed to close multipart writer: %v", err)
	}

	// 4. Create the HTTP request
	req := httptest.NewRequest(http.MethodPost, "/any-url", &formBuffer)
	// Set the correct Content-Type header, which includes the auto-generated boundary string
	req.Header.Set("Content-Type", multipartWriter.FormDataContentType())

	// 5. Capture the handler's response
	responseRecorder := httptest.NewRecorder()

	// 6. Call your handler directly
	DownloadFiles(responseRecorder, req)

	// Optional: Verify the handler returned the expected status code
	if responseRecorder.Code != http.StatusOK {
		t.Errorf("Expected status %d, got %d", http.StatusOK, responseRecorder.Code)
	}
}

Critical Tips to Avoid Headaches

  • Exact field name match: Your handler looks for the field documents, so don't typo this when calling CreateFormFile — a mismatch will result in an empty files slice.
  • Always close the multipart writer: Skipping this leaves the form data incomplete, and r.ParseMultipartForm will fail to parse it correctly.
  • Use httptest tools: httptest.NewRequest and httptest.ResponseRecorder are the standard way to test Go HTTP handlers without needing a live server.

内容的提问来源于stack exchange,提问作者NeariX

火山引擎 最新活动