Reputation: 207
I'm using Python 2.7 with Mock. I have a method that takes a url and downloads it into a temporary file, then renames file according to business logic rules. I want to test this renaming logic, but first I must mock the file download part. And here is where I'm stuck. I'm using urllib2.urlopen
and its read(chunkSize)
method in infinite cycle, checking if read(chunkSize)
returns some value. While this approach works in real life, and the response is eventually read up to the end where read(chunkSize)
does not return anything, I get an infinite cycle when mocking. read(chunkSize)
seems to always have a result. How do I get the cycle to stop once the contents of the response has been read? Here's my code:
import urllib2
from contextlib import closing
import unittest
import mock
def Method(url, temppath):
chunkSize = 16 * 1024
request = urllib2.Request(url)
with closing(urllib2.urlopen(request, timeout = 5)) as response:
with open(temppath, 'wb') as largeFile:
while True:
chunk = response.read(chunkSize)
# print chunk # <- this will endlessly produce '0123456' when tested by test_Method in MyTestCase
if not chunk:
break
largeFile.write(chunk)
# rename file from temppath to something new
class MyTestCase(unittest.TestCase):
@mock.patch('urllib2.urlopen', autospec=True)
@mock.patch('__main__.open', create=True)
def test_Method(self, mock_open, mock_urlopen):
mock_urlopen.return_value.read.return_value = b'0123456'
Method('http://a.bcd/img.png', 'a:\\b\\1234567890.tmp')
if __name__ == '__main__':
unittest.main()
Upvotes: 2
Views: 4269
Reputation: 1122532
Assign a list of values to return to the side_effect
attribute:
mock_urlopen.return_value.read.side_effect = [b'0123456', b'']
The mock will iterate over the values for each read()
call, so the last call returning an empty bytes object terminates your loop.
Upvotes: 4