使用Python请求和响应模拟下载文件

时间:2016-05-17 15:49:35

标签: python unit-testing python-requests

我有一些python代码,可以使用requests从网址成功下载图片,并将其保存到/tmp/。我想测试它做了它应该做的事情。我使用responses来测试获取JSON文件,但我不确定如何模拟获取文件的行为。

我认为它类似于嘲笑标准回复,如下所示,但我认为我在如何将body设置为文件...

@responses.activate
def test_download():
    responses.add(responses.GET, 'http://example.org/images/my_image.jpg',
              body='', status=200,
              content_type='image/jpeg')
    #...

更新:按照Ashafix的评论,我试试这个(python 3):

from io import BytesIO

@responses.activate
def test_download():
    with open('tests/images/tester.jpg', 'rb') as img1:
        imgIO = BytesIO(img1.read())

    responses.add(responses.GET, 'http://example.org/images/my_image.jpg',
              body=imgIO, status=200,
              content_type='image/jpeg')
    imgIO.seek(0)
    #...

但随后,当我测试的代码尝试执行请求时,我得到了:

a bytes-like object is required, not '_io.BytesIO'

感觉它几乎是正确的,但我很难过。

更新2:尝试关注Steve Jessop的建议:

@responses.activate
def test_download():
    with open('tests/images/tester.jpg', 'rb') as img1:
        responses.add(responses.GET, 'http://example.org/images/my_image.jpg',
                  body=img1.read(), status=200,
                  content_type='image/jpeg')
        #...

但这次正在测试的代码提出了这个问题:

I/O operation on closed file.

当然,图像仍应在with区域内打开?

更新3 :我测试的代码是这样的:

r = requests.get(url, stream=True)
if r.status_code == 200:
     with open('/tmp/temp.jpg', 'wb') as f:
        r.raw.decode_content = True
        shutil.copyfileobj(r.raw, f)

似乎最终shutil行正在关闭文件上生成" I / O操作。"错误。我不太了解这一点 - 文件流 - 知道如何最好地模仿这种行为,测试下载的文件保存到/tmp/

2 个答案:

答案 0 :(得分:5)

您可能需要将stream=True传递给responses.add来电。类似的东西:

@responses.activate
def test_download():
    with open('tests/images/tester.jpg', 'rb') as img1:
        responses.add(
            responses.GET, 'http://example.org/images/my_image.jpg',
            body=img1.read(), status=200,
            content_type='image/jpeg',
            stream=True
        )

似乎适用于我的案例。

答案 1 :(得分:1)

首先,总结一下我现在过长的问题......我正在测试一些类似的代码:

def download_file(url):
    r = requests.get(url, stream=True)
    if r.status_code == 200:
         filename = os.path.basename(url)
         with open('/tmp/%s' % filename, 'wb') as f:
            r.raw.decode_content = True
            shutil.copyfileobj(r.raw, f)
         return filename

下载图像,然后将其保存到/tmp/。我想模仿请求,以便我可以测试其他内容。

@responses.activate
def test_downloads_file(self):
    url = 'http://example.org/test.jpg'
    with open('tests/images/tester.jpg', 'rb') as img:
        responses.add(responses.GET, url,
                        body=img.read(), status=200,
                        content_type='image/jpg',
                        adding_headers={'Transfer-Encoding': 'chunked'})
        filename = download_file(url)
        # assert things here.

一旦我找到了使用open()的方法,我仍然在关闭文件上进行" I / O操作。"来自shutil.copyfileobj()。停止此操作的是添加Transfer-Encoding标头,当我发出真实请求时,标头中会出现标题。

对其他更好的解决方案的任何建议都非常欢迎!