0

I have an issue with tests, specifically with mocking a request with unittest.mock.patch and requests: this is the function to test:

import os
from http import HTTPStatus

import requests
from requests.exceptions import RequestException

from .exceptions import APIException



logger = logging.getLogger("my_project")


def request_ouath2_token(dict_data, debugging=False):
    """
    request oauth2 token from COMPANY
    """
    api_endpoint = "{}/services/api/oauth2/token".format(
        dict_data['https_domain']
    )
    headers = {
        'Content-Type': 'application/json',
        'cache-control': 'no-cache'
    }
    data = {
        'clientId': dict_data['clientId'],
        'clientSecret': dict_data['clientSecret'],
        'grantType': 'client_credentials',
        'scope': 'all'
    }
    if debugging:
        logger.debug('COMPANY AUTH API: {}'.format(api_endpoint))
    response = requests.post(api_endpoint, json=data, headers=headers)
    try:
        response.raise_for_status()
    except RequestException as _e:
        raise APIException("error on requesting a new OAuth2 access token, error: {}".format(str(_e)))
    content = response.json()
    return content

and this is the test:

# test module

import os
import unittest
import warnings
from unittest.mock import patch, Mock
import json
from http import HTTPStatus

from myapp.api import auth, exceptions as api_exceptions



class AuthHelpersTestCase(unittest.TestCase):
    """
    auth test helper class
    """
    def setUp(self):
        self.secret = "my secret"
        self.decoded_secret = base64.b64decode(self.secret)
        self.token = "my token"
        self.url = "/my/relative/url"
        self.user = "my user"
        self.portal = "my-portal"
        self.api_key = "my api key"
        self.oauth2_client_id = "my ouath2 client id"
        self.oauth2_client_secret = "my ouath2 client secret"
        self.oauth2_token_exp_secs = 3600
        self.oauth2_obtained_access_token = 'obtained-oauth2-access-token'
        self.alias = '{}_{}'.format(self.user, int(datetime.utcnow().strftime("%s")))


    def test_request_ouath2_token_failure(self):
        with patch('requests.post') as mock_request:
            rsp_content, data_dict = self._mock_request_ouath2_token_config()
            mock_response = Mock()
            mock_response.status_code = HTTPStatus.UNAUTHORIZED.value
            mock_response.content = json.dumps(rsp_content)
            mock_request.return_value = mock_response
            with self.assertRaises(api_exceptions.APIException) as cm:
                auth.request_ouath2_token(data_dict)
                self.assertEqual(cm.exception, api_exceptions.APIException)

it seems that the exception is not raised in my function, besides the mocked response status code is 500; it seems that raise_for_status() does not catch it.

result:

======================================================================
ERROR: test_request_ouath2_token_failure (tests.test_auth.AuthHelpersTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/myuser/PycharmProjects/company/tests/test_auth.py", line 165, in test_request_ouath2_token_failure
    self.assertEqual(cm.exception, api_exceptions.APIException)
AttributeError: '_AssertRaisesContext' object has no attribute 'exception'

any idea of why? am I missing something?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Luke
  • 1,794
  • 10
  • 43
  • 70
  • If your code even got that far, then it didn't raise any exception. Because an exception would have kicked you out of the with block already. – wim Dec 16 '19 at 22:36
  • 1
    your cm, literally doesn't have any method called exception. You can do `cm.__dict__.keys()` or `dir(cm)` to list all methods. Can paste the source code of `.exception` ? – Lucas Vazquez Dec 16 '19 at 22:42
  • @LucasVazquez yes there isn't an `exception` key in `cm.__dict__`. However, if I raise manually an `APIException` in `request_ouath2_token`, the test pass. – Luke Dec 17 '19 at 08:54

1 Answers1

0
  1. When you use the returned value of assertRaises as a context manager, you should check the result outside the block. Remember, you are asserting that an exception should be raised.
  2. In your code self.assertEqual(cm.exception, api_exceptions.APIException) was reached because the line before it didn't raise an exception.
  3. Try to print(requests.post) in request_oauth2_token, if you don't see a mock object it means your patching doesn't work. If the module containing request_ouath2_token is called x_mod, you should try to patch it with something like patch.object(x_mod.requests, "post").
Floyd
  • 2,252
  • 19
  • 25
satoru
  • 31,822
  • 31
  • 91
  • 141