Search code examples
djangounit-testingjwtmocking

Django how to mock access token


I have the following code in my testcase. Whenever I'm running the testcase, a new token is generated which is draining my quota.

So,instead of actual token I want to use some mock value which needs to be authenticated by the APIClient successfully. How do I mock this token authentication ?
Any help is much appreciated. Thanks

Settings

'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTStatelessUserAuthentication',
],

Testcase

from apps.common.helpers import get_auth0_access_token

class TestDatasetListTestCase(APITestCase):
    def setUp(self):
        access_token = get_auth0_access_token()
        self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {access_token}")

        payload = {"label": "new_label"}
        response = self.client.post(self.url, payload, format="multipart")

helpers.py

def generate_new_auth0_token()
    options = {
        "url": f"https://{auth0_domain}/oauth/token",
        "headers": {"cache-control": "no-cache", "content-type": "application/json"},
        "json": {"audience": audience, "grant_type": grant_type, "client_id": client_id, "client_secret": client_secret},
    }
    res = requests.post(**options)
    return res.json() or Exception(res.text)

Solution

  • In unit tests, the standard procedure for external APIs is to have them mocked. There is no point in calling these APIs during tests because these are expected to work unless something changes on the other side (like changing APIs), but it is not expected in your case because you are using a standard API (with a fixed set of specifications by oAuth), unless the client server is down.

    class TestDatasetListTestCase(APITestCase):
       @mock.patch('apps.common.helpers.get_auth0_access_token')
       def test_access_token(self, mock_access_token):
            mock_access_token.return_value = SomeFactory().get_test_access_token()  # just using Factory pattern here, it can be hard coded string
            access_token = get_auth0_access_token()
            self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {access_token}")
    
            payload = {"label": "new_label"}
            response = self.client.post(self.url, payload, format="multipart")
    

    If you still willing to to test APIClient, then I suggest setting up a mock oAuth server, like this opensource project Mock oAuth Server. Then you can provide the test url the API calls (Or mock it). Lets say your url is defined in settings, you can try like this:

    from django.test import override_settings
    
    @override_settings(API_AUTH_URL='http://localhost:8989', CLIENT_SECRET='something', CLIENT_ID='else')
    class TestDatasetListTestCase(APITestCase):
    

    And update the helper function:

    def generate_new_auth0_token()
        options = {
            "url": f"https://{settings.API_AUTH_URL}/oauth/token",
            "headers": {"cache-control": "no-cache", "content-type": "application/json"},
            "json": {"audience": audience, "grant_type": grant_type, "client_id": settings.CLIENT_ID, "client_secret": settings.CLIENT_SECRET},
        }
    

    More information can be found in the documentation regarding settings override.