Python 3 urlopen context manager mocking Python 3 urlopen context manager mocking python-3.x python-3.x

Python 3 urlopen context manager mocking


I was fighting with this as well, and finally figured it out. (Python 3 syntax):

import urllib.requestimport unittestfrom unittest.mock import patch, MagicMockclass TestUrlopen(unittest.TestCase):    @patch('urllib.request.urlopen')    def test_cm(self, mock_urlopen):        cm = MagicMock()        cm.getcode.return_value = 200        cm.read.return_value = 'contents'        cm.__enter__.return_value = cm        mock_urlopen.return_value = cm        with urllib.request.urlopen('http://foo') as response:            self.assertEqual(response.getcode(), 200)            self.assertEqual(response.read(), 'contents')    @patch('urllib.request.urlopen')    def test_no_cm(self, mock_urlopen):        cm = MagicMock()        cm.getcode.return_value = 200        cm.read.return_value = 'contents'        mock_urlopen.return_value = cm        response = urllib.request.urlopen('http://foo')        self.assertEqual(response.getcode(), 200)        self.assertEqual(response.read(), 'contents')        response.close()


here is my take on this

from urllib.request import urlopen from unittest.mock import patchclass Mock():    def __init__(self, request, context):        return None    def read(self):        return self    def decode(self, arg):        return ''    def __iter__(self):        return self    def __next__(self):        raise StopIteration with patch('urllib.request.urlopen',  Mock):    # do whatever over here


with urlopen('some url here') as data is a context manager

Also, a file can be used as a context manager, so a better approach here is to use io.StringIO

import ioimport jsonimport urllib.requestfrom unittest.mock import patchdef get_posts():    with urllib.request.urlopen('some url here') as data:        return json.load(data)def test_get_posts():    data = io.StringIO('{"id": 123}')    with patch.object(urllib.request, 'urlopen', return_value=data):        assert get_posts() == {"id": 123}