0

I am having trouble understanding how mocking works when the get responses involve using the with keyword. Here is an example I am following for my class `Album' and I have been successful when I am mocking a url as seen below:

def find_album_by_id(id):
    url = f'https://jsonplaceholder.typicode.com/albums/{id}'
    response = requests.get(url)
    if response.status_code == 200:
        return response.json()['title']
    else:
        return None

Here the test

class TestAlbum(unittest.TestCase):

    @patch('album.requests')
    def test_find_album_by_id_success(self, mock_requests):
        # mock the response
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            'userId': 1,
            'id': 1,
            'title': 'hello',
        }

        # specify the return value of the get() method
        mock_requests.get.return_value = mock_response

        # call the find_album_by_id and test if the title is 'hello'
        self.assertEqual(find_album_by_id(1), 'hello')

However, I am trying to understand how this would work with the with keyword involved in the code logic which I am using in my project. This is how I changed the method

def find_album_by_id(id):
    url = f'https://jsonplaceholder.typicode.com/albums/{id}'
    with requests.get(url) as response:
        pipelines = response.json()
    if response.status_code == 200:
        return pipelines['title']
    else:
        return None

Here is my current test:

   @patch('album.requests.get') 
    def test_find_album_by_id_success(self, mock_requests):
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.pipelines.response.json = {
            'userId': 1,
            'id': 1,
            'title': 'hello',
        }
       
        mock_requests.return_value.json.return_value = mock_response
      
        self.assertEqual(find_album_by_id(1), 'hello')

Thanks

I have tried debugging the test and it just never receives the status code of 200 so I am not sure I am mocking response correctly at all? From my understanding the mock_response is supposed to have that status code of 200 but breakline indicates that response is just a MagicMock with nothing in it.

Lee
  • 1
  • 1
  • Where are you *using* `mock_response`? You define and configure it, but then use something called `expected` to configure the mock (a *different* mock) returned by `mock_requests` when it gets called. – chepner Dec 16 '22 at 17:19
  • apologies, expected should be mock_response, edited the code – Lee Dec 16 '22 at 17:22
  • Not much needs to change from your original test. The `__enter__` method returns the same `Response` object that `requests.get` produces; the context manager simply closes the response, AFAIK only useful if you decide to finish with a *streaming* response before consuming the entire result. – chepner Dec 16 '22 at 17:22
  • Yeah from my understanding, mock_response is what should be 'mocking' the response with requests.get is called. By that logic response would equal the mock_response object. So when it checks if the status code is 200, it should dive into that return but it does not. Rather it is a blank magic_mock object – Lee Dec 16 '22 at 17:25
  • You are trying to use `mock_response` as the return value of the `json` method of some `Response` object, not the `Response` object itself. – chepner Dec 16 '22 at 17:31
  • I think the only thing that needs to change from your original test is that `mock_response` should be the return value of `mock_requests.return_value.__enter__`. (Noting that `mock_requests` itself is replacing `requests.get` instead of `requests` itself in the new test.) – chepner Dec 16 '22 at 17:36
  • If I am understanding correctly, what you are saying is that I want to mock the return value of the object I get from response. Hence, I would make `mock_requets.return_value.__enter__ = mock_response` ? Is there a better way to achieve this? I tried doing this but it also is not really working. – Lee Dec 16 '22 at 17:56
  • `mock_requests.return_value.__enter__.return_value = mock_response`. – chepner Dec 16 '22 at 18:00

0 Answers0