pytest本身不处理HTTP请求,正确做法是用requests或框架测试客户端(如FastAPI的TestClient)的files参数传元组,如{"file": ("f.jpg", open("f.jpg", "rb"), "image/jpeg")},避免手动构造multipart body。

pytest怎么模拟multipart/form-data文件上传
直接用 requests.post 发原始二进制数据容易出错,关键在于构造符合 RFC 7578 的 multipart body —— pytest 本身不处理 HTTP 请求,真正干活的是 requests 或测试客户端(如 FastAPI 的 TestClient、Flask 的 test_client),pytest 只负责组织断言和 fixture。
常见错误现象:400 Bad Request 或后端解析出空文件,多半是 files 参数格式不对,或没传 Content-Type(其实不用手动设,requests 会自动加带 boundary 的 multipart/form-data)。
- 正确写法:用
files参数传元组,格式为{"file": ("filename.jpg", file_obj, "image/jpeg")} - 如果读取本地文件,用
open("test.jpg", "rb"),别用文本模式 - 内存中构造小文件可用
io.BytesIO(b"fake image data"),避免依赖磁盘 - 多文件上传时,
files可传列表,如[("files", f1), ("files", f2)](注意字段名一致)
FastAPI/Flask测试中如何用TestClient发文件
Web 框架的测试客户端比裸 requests 更可靠,它绕过网络栈,直接调用路由函数,能捕获更清晰的错误堆栈。
使用场景:你用的是 FastAPI?Flask?还是 Django?对应客户端初始化方式不同,但发文件逻辑高度一致。
立即学习“Python免费学习笔记(深入)”;
- FastAPI:
from fastapi.testclient import TestClient,实例化后调用client.post("/upload", files=...) - Flask:
app.test_client(),同样支持.post(..., files=...) - Django 要用
django.test.Client().post(..., data=..., format="multipart"),且需确保视图用了request.FILES - 注意:FastAPI 的
UploadFile参数必须标注类型提示,否则测试客户端无法正确绑定
怎么测文件大小超限、类型不匹配等边界情况
光测“上传成功”没意义。真实接口必有校验逻辑,比如 max_file_size=5*1024*1024 或只允许 ["png", "jpg"],这些必须在测试里覆盖。
性能影响:用大文件做测试会拖慢 CI,建议用 io.BytesIO 构造刚好超限的假数据(比如 5_000_001 字节),而不是真写一个 5MB 文件到磁盘。
- 测超限:构造
BytesIO(b"x" * (max_size + 1)),检查返回413 Payload Too Large或自定义错误码 - 测非法类型:传
("evil.exe", b"...", "application/x-msdownload"),验证是否被拒绝(状态码或响应体含 "invalid type") - 测空文件:
("empty.txt", b"", "text/plain"),看后端是否判空并返回400 - 别忘了测
filename为空或含路径遍历字符(如"../etc/passwd"),验证服务端是否做了清理
为什么测试里总遇到UnicodeDecodeError或Missing boundary
这基本等于你误把字符串当二进制用了。multipart body 必须是 bytes,而 Python 3 默认字符串是 Unicode,混用就会炸。
容易踩的坑:
- 用
open("f.txt").read()(文本模式)代替open("f.txt", "rb").read()→ 报UnicodeDecodeError - 手动拼接 multipart body 字符串(比如用
f"""--{boundary}...""")→ 缺少 CRLF、boundary 不匹配 →Missing boundary或解析失败 - 用
json.dumps(...)当请求体,却还传files=...→requests会忽略files,因为json和files互斥 - 忘记关闭
BytesIO或文件句柄 → 小概率导致后续测试读不到内容(尤其 Windows)
边界 case 的构造比主流程更费神,尤其是 filename 编码、空字节、超长名这些,实际攻防中常被利用,但测试里最容易漏掉。


















