Python Django单元测试中如何为伪造HTTP请求添加请求体?
Django单元测试中伪造带XML请求体的POST请求
问题描述
在Python Django项目里,我们想通过单元测试给被测函数传入HTTP POST请求。原本用cURL命令会触发Web服务器端点的完整逻辑路径,但我们希望单元测试聚焦于接收request参数的特定函数。已经拿到伪造HTTP请求的Python代码,但不知道怎么像cURL的-d参数那样,把XML格式的请求体传入伪造的请求对象中。
相关技术细节
cURL命令
curl http://127.0.0.1:8000/api/transaction/ --insecure \ --verbose \ -d '<env:Envelope ... > <env:Header> ... </env:Header> <env:Body> ... </env:Body> </env:Envelope> '
现有伪造请求代码
from django.core.handlers.wsgi import WSGIRequest from io import StringIO from django.contrib.auth.models import AnonymousUser def GetFakeRequest(path='/', user=None): """ Construct a fake request(WSGIRequest) object""" req = WSGIRequest({ 'REQUEST_METHOD': 'GET', 'PATH_INFO': path, 'wsgi.input': StringIO()}) req.user = AnonymousUser() if user is None else user return req
解决方案
要伪造带XML请求体的POST请求,需要对现有函数做以下关键调整:
- 修改请求方法为POST
- 将XML内容转为字节流传入
wsgi.input - 设置匹配XML类型的
CONTENT_TYPE头和正确的CONTENT_LENGTH
修改后的完整代码:
from django.core.handlers.wsgi import WSGIRequest from io import BytesIO # WSGI要求wsgi.input为字节流,替换StringIO from django.contrib.auth.models import AnonymousUser def GetFakePostRequestWithXml(path='/', user=None, xml_body=''): """构造带XML请求体的伪造POST请求对象""" # 将XML字符串编码为字节流 xml_bytes = xml_body.encode('utf-8') wsgi_input = BytesIO(xml_bytes) req = WSGIRequest({ 'REQUEST_METHOD': 'POST', 'PATH_INFO': path, 'wsgi.input': wsgi_input, 'CONTENT_TYPE': 'text/xml; charset=utf-8', 'CONTENT_LENGTH': str(len(xml_bytes)), # 可选:添加与cURL一致的请求头,比如Accept 'HTTP_ACCEPT': '*/*', }) req.user = AnonymousUser() if user is None else user return req
使用示例
# 定义XML请求体 xml_payload = '''<env:Envelope ... > <env:Header> ... </env:Header> <env:Body> ... </env:Body> </env:Envelope>''' # 生成伪造请求 fake_request = GetFakePostRequestWithXml( path='/api/transaction/', xml_body=xml_payload ) # 传入被测函数执行测试 result = your_target_function(fake_request)
关键注意点
- 必须用
BytesIO:WSGI规范要求wsgi.input是字节流对象,不能用处理字符串的StringIO,否则Django无法正确解析请求体。 - 不能省略
CONTENT_LENGTH:Django的WSGIRequest会依赖这个值读取请求体内容,缺失会导致无法获取XML数据。 - 匹配实际的
CONTENT_TYPE:如果接口期望application/xml,需要对应修改这个头的值,和cURL请求保持一致。
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

