go测试文件上传应使用multipart.writer自动生成边界符和换行符,避免手拼导致解析失败;下载测试直接读取resp.body校验二进制内容;handler测试需注入内存buffer替代磁盘i/o;必须覆盖空文件、超大文件、非法mime等边界场景。

Go 测试文件上传:用 multipart.Writer 构建真实请求体
直接用 bytes.Buffer 拼接 multipart 数据容易出错,边界符(boundary)不匹配、换行符混用(\r\n vs \n)会导致服务端解析失败,返回 http.StatusBadRequest 或空 *multipart.Form。
正确做法是让标准库自己生成——用 multipart.Writer 写入字段和文件流,再把底层 bytes.Buffer 作为 io.Reader 传给 http.NewRequest:
buf := &bytes.Buffer{}
w := multipart.NewWriter(buf)
w.WriteField("name", "report.pdf")
f, _ := w.CreateFormFile("file", "report.pdf")
f.Write([]byte("fake content"))
w.Close() // 必须调用,否则 boundary 不闭合
req, _ := http.NewRequest("POST", "/upload", buf)
req.Header.Set("Content-Type", w.FormDataContentType()) // 关键:用 Writer 提供的 type
注意:w.FormDataContentType() 返回带正确 boundary 的 multipart/form-data,硬编码会失效。
Go 测试文件下载:捕获响应 Body 并校验二进制内容
下载接口通常返回 Content-Disposition: attachment; filename=...,但测试时你真正关心的是响应体是否为预期字节流,而不是浏览器行为。
立即学习“go语言免费学习笔记(深入)”;
直接读取 resp.Body 即可,无需启动 HTTP 服务器或写临时文件:
resp, _ := http.Get("/download?id=123")
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if len(body) == 0 {
t.Fatal("expected non-empty download body")
}
if !bytes.Equal(body, []byte("expected file content")) {
t.Fatal("download content mismatch")
}
常见坑:resp.Body 是流式读取,只可读一次;忘记 defer resp.Body.Close() 会导致连接泄漏;用 resp.Body.String() 会丢弃非 UTF-8 字节(比如 PDF、ZIP)。
Mock 文件上传 handler:避免依赖真实磁盘 I/O
测试 handler 逻辑时,别在测试里真写文件到磁盘——慢、不隔离、需清理。应该把 os.OpenFile 或 io.Copy 目标替换成内存 buffer 或 io.Discard。
推荐方式:通过函数参数或结构体字段注入写入目标,测试时传入 &bytes.Buffer{}:
func handleUpload(w http.ResponseWriter, r *http.Request) {
r.ParseMultipartForm(32 << 20)
file, _, _ := r.FormFile("file")
defer file.Close()
// 不要写死:dst, _ := os.Create("/tmp/uploaded.pdf")
dst := testOutputBuffer // 测试时注入
io.Copy(dst, file)
}
这样测试能直接断言 testOutputBuffer.Bytes() 是否符合预期,且无副作用。
边界场景必须覆盖:空文件、超大文件、非法 MIME 类型
真实用户会传空文件、截断的 ZIP、或把 .exe 改名成 .pdf。测试不能只跑“happy path”。
- 空文件:用
w.CreateFormFile("file", "empty.txt")后不写任何字节,检查 handler 是否返回http.StatusBadRequest - 超大文件:用
io.LimitReader控制上传体大小,验证ParseMultipartForm的 maxMemory 限制是否生效 - 非法类型:手动设置
req.Header.Set("Content-Type", "text/plain"),确认 handler 拒绝非multipart/form-data
multipart 边界解析对换行敏感,Windows 和 Linux 下生成的测试数据可能因 \r\n 缺失而失败——始终用 multipart.Writer,别手拼。










