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



我有一些python代码,它使用请求成功地从URL下载图像,并将其保存到/tmp/中。我想测试一下它应该做什么。我正在使用响应来测试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/

您可能需要将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,
        )

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

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()的方法,我仍然可以从shutil.copyfileobj()获得"关闭文件的I/O操作"。停止此操作的方法是添加Transfer-Encoding标头,当我发出真正的请求时,它会出现在标头中。

欢迎对其他更好的解决方案提出任何建议!

最新更新