【问题标题】:How can I use requests_mock to unit test a file upload?如何使用 requests_mock 对文件上传进行单元测试?
【发布时间】:2018-08-06 21:13:24
【问题描述】:

我正在为 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)

我已经确定,在成功上传文件后,validate_file_uploadrequest 参数有几个相关的数据位,即request.headersrequest.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'

现在,事情就是这样。我知道我可以解析 request.text 字符串并获得我想要的数据;这很容易验证。

但是,这种逻辑似乎真的不属于我的单元测试。我无法想象没有更好的解决方案。要么有人已经在不同的模块中实现了这个功能,要么我忽略了一些明显的东西。

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


这是dir(request)的输出:

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattr__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_allow_redirects', '_case_sensitive', '_cert', '_create', '_matcher', '_proxies', '_qs', '_request', '_stream', '_timeout', '_url_parts', '_url_parts_', '_verify', 'allow_redirects', 'cert', 'hostname', 'json', 'matcher', 'netloc', 'path', 'port', 'proxies', 'qs', 'query', 'scheme', 'stream', 'text', 'timeout', 'verify']

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

【问题讨论】:

    标签: python python-requests python-unittest


    【解决方案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`
    

    【讨论】:

      【解决方案2】:

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

      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

      【讨论】:

        猜你喜欢
        • 2012-06-25
        • 2017-04-13
        • 2021-09-18
        • 2019-05-21
        • 1970-01-01
        • 2016-11-19
        • 2014-02-23
        相关资源
        最近更新 更多