Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python 3 urlopen context manager mocking

I am new to testing and need some help here.

Assuming having this method:

from urllib.request import urlopen

def get_posts():
    with urlopen('some url here') as data:
        return json.loads(data.read().decode('utf-8'))

The question is how to test this method (using mock.patch decorator if possible)?

What I have now:

@mock.patch('mymodule.urlopen')
def test_get_post(self, mocked_urlopen):
    mocked_urlopen.__enter__ = Mock(return_value=self.test_data)
    mocked_urlopen.__exit__ = Mock(return_value=False)
    ...

But it does not seem to be working.

P.S. Is there any convenient way to work with data variable (which type is HTTPResponse) in test so it could just be simple string?

like image 228
Yevs Avatar asked Aug 17 '15 04:08

Yevs


Video Answer


2 Answers

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

import urllib.request
import unittest
from unittest.mock import patch, MagicMock

class 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()
like image 141
Martin Pitt Avatar answered Oct 13 '22 19:10

Martin Pitt


here is my take on this

from urllib.request import urlopen 
from unittest.mock import patch

class 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
like image 39
isnvi23h4 Avatar answered Oct 13 '22 20:10

isnvi23h4