alec.tu
alec.tu

Reputation: 1757

How to mock urllib2 with standard mock library

I faced a similar problem with Mocking urllib2.urlopen().read() for different responses

But the solution not work for me.

My mock object always return <MagicMock name='urlopen().read()' id='140016097869776'> when I want to mock the urlopen object.

Here is what I want to test, mod.py

import urllib2
from zipfile import ZipFile
from io import BytesIO
def verify(url, checksum):
    try:
        conn = urllib2.urlopen(url)
        byte = conn.read()
        conn.close()           
        myzip = ZipFile(BytesIO(byte))
    except Exception as e:
        err = get_error(400, "Not a valid zip format: %s" % (str(e)))
        return Response(err, status=status.HTTP_400_BAD_REQUEST)
    return byte

Here is what I mock

@mock.patch('mod.urllib2.urlopen')
@mock.patch('mod.ZipFile')
@mock.patch('mod.BytesIO')
def test_verify(self, urlopen_mock, zipfile_mock, bytesio_mock):
    conn = mock.Mock()
    conn.read.return_value = 'byte'
    urlopen_mock.return_value = conn
    zf = mock.Mock()
    zipfile_mock.return_value = zf
    assertEqual(verify('url','checksum'), 'byte')

However, the returned byte is always <MagicMock name='urlopen().read()' id='140016097869776'>, not 'byte' as I mock.

Is something important I miss?

Upvotes: 0

Views: 597

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 599788

You need to define read on the return value of conn:

conn.return_value.read.return_value = 'byte'

Edit I misdiagnosed the problem. The actual issue is that the method arguments are passed in reverse order to the way the decorators are applied: so your signature should be:

def test_verify(self, bytesio_mock, zipfile_mock, urlopen_mock):

Upvotes: 1

Related Questions