Search code examples
pythontestingpython-requestspytestmonkeypatching

Monkeypatch imported functions requests module [Pytest]


I faced a problem that I needed to test a function which called requests. The recomemended way is to use monkeypatch to avoid the request call, but all the resources showed a way to do that with the requests module outside the function:

import requests


def test_get_credentials(uri, code):
#the actual function, but rewritten here instead of just being imported

    def mocked_get(uri, *args, **kwargs):
    # this is a request answer mock to avoid calling external servers during tests
        json = {"token_type": "JWT", "access_token": "ioaUSHDAHwe9238hidnfiqh2wr89o"}
        mock = type("MockedReq", (), {})()
        mock.json = json
        obj = mock
        return obj

    monkeypatch.setattr(requests, "post", mocked_get)    

    credentials = requests.post(uri, data=code).json()
    assert credentials == {"token_type": "JWT", "access_token": "ioaUSHDAHwe9238hidnfiqh2wr89o"}

But I wanted to use the imported function and didn't find a way to patch the requests module from the imported function. Something like:

import requests
from external_auth import get_credentials

def test_get_credentials(uri, code):
    def mocked_get(uri, *args, **kwargs):
            json = {"token_type": "JWT", "access_token": "ioaUSHDAHwe9238hidnfiqh2wr89o"}
            mock = type("MockedReq", (), {})()
            mock.json = json
            obj = mock
            return obj

        monkeypatch.setattr(requests, "post", mocked_get)

    assert get_credentials(uri, code) == {"token_type": "JWT", "access_token": "ioaUSHDAHwe9238hidnfiqh2wr89o"}

Solution

  • The way I found to patch the imported function is through the __globals__ function attribute changing get_credentials.__globals__["requests"] instead of just get_credentials. The final code looked like:

    import requests
    from external_auth import get_credentials
    
    def test_get_credentials(uri, code):
        def mocked_get(uri, *args, **kwargs):
            json = {"token_type": "JWT", "access_token": "ioaUSHDAHwe9238hidnfiqh2wr89o"}
            mock = type("MockedReq", (), {})()
            mock.json = json
            obj = mock
            return obj
    
        monkeypatch.setattr(get_credentials.__globals__["requests"], "post", mocked_get)
    
        assert get_credentials(uri, code) == {"token_type": "JWT", "access_token": "ioaUSHDAHwe9238hidnfiqh2wr89o"}