如何使用request_mock对文件上传进行单元测试?

时间:2018-08-06 21:13:25

标签: python python-requests python-unittest

我正在为API编写Python(3)包装器,并且尝试对需要上传文件的部分进行单元测试。我想验证文件名和内容是否由客户端正确发送。

我正在使用Python的unittest库以及requestsrequests_mock进行测试。

我计划解决此问题的方法是具有一个回调函数来验证文件是否已发送并且所有标头均已正确设置。这是我到目前为止的内容:

import unittest
import requests
import requests_mock

from my_class import my_class

from my_class.API import API

class  TestAPI(unittest.TestCase):

    def setUp(self):
        self.hostname = 'https://www.example.com'

    def validate_file_upload(self, request, context, filename, content):
        # self.assertEqual(something, something_else)
        # better solution goes here

    def test_submit_file(self):
        API_ENDPOINT = self.hostname + '/api/tasks/create/file/'
        DUMMY_FILE = 'file'
        DUMMY_CONTENT = 'here is the\ncontent of our\nfile'

        s = API(self.hostname)

        with open(DUMMY_FILE, 'w+') as f:
            f.write(DUMMY_CONTENT)

        with requests_mock.Mocker() as m:
            def json_callback(request, context):
                self.validate_file_upload(request, context, DUMMY_FILE,
                    DUMMY_CONTENT)
                return {}

            m.post(API_ENDPOINT, json=json_callback)
            s.upload_file(DUMMY_FILE)

我确定,在成功上传文件后,request的{​​{1}}参数具有几个相关的数据位,即validate_file_uploadrequest.headers。在调用request.text函数之后,这两个都包含以下内容:

validate_file_upload

request.headers

{'User-Agent': 'python-requests/2.19.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '171', 'Content-Type': 'multipart/form-data; boundary=e1a0aa05f83735e85ddca089c450a21b'}

request.text

现在,这是东西。我知道自己可以解析 '--e1a0aa05f83735e85ddca089c450a21b\r\nContent-Disposition: form-data; name="file"; filename="file"\r\n\r\nhere is the\ncontent of our\nfile\r\n--e1a0aa05f83735e85ddca089c450a21b--\r\n' 字符串并获取所需的数据;验证起来很容易。

但是,这种逻辑似乎真的不属于我的单元测试。我无法想象没有更好的解决方案。有人已经在其他模块中实现了此功能,或者我忽略了明显的内容。

我不需要为文件上传实现HTTP spec 来进行像文件上传一样简单的单元测试,对吧?有更好的方法吗?


这是request.text的输出:

dir(request)

我已经检查了所有非下划线属性,以获取文件上传数据的任何其他表示形式,但无济于事。我也尝试过搜索StackOverflowGoogle,并且距离寻找一种更好的方法还很近。这是唯一出现在这两个搜索中的帖子。

2 个答案:

答案 0 :(得分:1)

我没有my_class.API可以测试您的确切代码,但是我相信您可以使用cgi

import cgi

body_file = io.BytesIO(request.body)
_, pdict = cgi.parse_header(request.headers['Content-Type'])
parsed = cgi.parse_multipart(fp=body_file, pdict=pdict)
# Now inspect `parsed`

答案 1 :(得分:0)

暂时,我决定采用这种相当简单的方法:

def validate_file_upload(self, request, context, filename, content):
    self.assertTrue(filename in request.text)
    self.assertTrue(content in request.text)

虽然它不是十全十美的,但与解析HTTP请求相比,它的逻辑要少得多,而且似乎至少对文件是否正确上传进行了基本验证。如前所述,我正在使用requests库,因此我不太担心弄乱文件上载,无论如何,这在大多数情况下都可以解决。

为防止名称filerequest.text中的其他名称不正确匹配,我将其更改为rather_unique_filename