10

I have made some changes to a functionality which is breaking the unit tests. Previously i had a common.py containing the function request_url:

import requests

def request_url(method, url):
    return _request_url(method, url)

def _request_url(method, url):
    return requests.request(method, url)

And this was the test:

@mock.patch("requests.request", autospec=True)
def test_request_url_200(self, mock_request):

    response = mock.MagicMock()
    response.status_code = 200
    method = mock.sentinel.method
    path = "url"

    result = common.request_url(
        method,
        path
    )

    self.assertListEqual([
        mock.call(
            mock.sentinel.method,
            "url"
        ),
    ], list(mock_request.mock_calls))

    self.assertListEqual([mock.call.raise_for_status()], list(response.mock_calls))
    self.assertEqual(mock_request.return_value, result)

After the changes in functionality, instead of simply calling requests.request, i have first initiated a session, mounted a TLS Adapter and then called the session's request function like this:

def _request_url(method, url):
    session = requests.session()
    adapter = TlsAdapter(ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1)
    session.mount("https://", adapter)
    return response = session.request(method, url)

Here, i am not sure how to exactly mock session.request since that is available through the session variable. I tried patching requests.session.request but that does not work here.

Does anyone have any idea how can this function be mocked?

thanks!

1 Answer 1

4

I think the reason in @mock.patch(...). You set autospec=True, but your mock_request doesn't return data(in your case everytime - Mock). The documentation says:

If you set autospec=True then the mock will be created with a spec from the object being replaced. All attributes of the mock will also have the spec of the corresponding attribute of the object being replaced. ...

Try to call:

print(mock_request.return_value) # <MagicMock name='request()()' id='4343989392'>
# or
# print(mock_request.return_value.return_value) # <MagicMock name='request()()()' id='4344191568'>

As you can see requests.request was 'mocked' but doesn't return any data. You can set expected data using return_value or side_effect. Here an example:

from unittest import TestCase
import mock
from common import request_url


class MyTestExample(TestCase):

    def test_request_url_1(self):
        mocked_request = mock.patch('requests.request', side_effect=['one', 'two', 'tree', ])
        mocked_request.start()
        # request_url(...) will return item from list
        self.assertEqual('one', request_url('test', 'url'))
        self.assertEqual('two', request_url('test', 'url'))
        self.assertEqual('tree', request_url('test', 'url'))

        mocked_request.stop()

    def test_request_url_2(self):
        result = {'my': 'dict'}
        mocked_request = mock.patch('requests.request', return_value=result)
        mocked_request.start()
        # request_url(...) will return static data 
        self.assertEqual(result, request_url('test', 'url'))
        self.assertEqual(result, request_url('test', 'url'))
        self.assertEqual(result, request_url('test', 'url'))

        mocked_request.stop()

So, you need just describe expected data. Also you can mock API using httpretty.

Hope this helps.

Sign up to request clarification or add additional context in comments.

2 Comments

yup it does! Thanks alot for pointing out the mistake in returning a value of mock!
To avoid confusions for future readers, I believe it has nothing to do with autospec at all. It's just that self.assertEqual(mock_request.return_value, result) literally compared mock_request.return_value to itself, since result came from calling mocked requests.request, i.e. return_value of the mock! :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.