Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

patch.multiple() returns an empty dictionary

I have a pytest fixture mocking multiple methods of an API client, using patch.multiple():

@pytest.fixture(scope='function', autouse=True)
def client_mock(request):    
    with patch.multiple(api_client,
                        method1=MagicMock(return_value=fixture1),
                        method2=MagicMock(return_value=fixture2),
                        method3=MagicMock(return_value=fixture3)) as mocks:
        yield mocks

This seems to work fine, however, when I try to access the mocks (by adding a client_mock parameter to a test function), I get an empty dictionary ({}). Why does it not contain any mocks?

like image 359
planetp Avatar asked Oct 29 '25 05:10

planetp


1 Answers

patch.multiple does not return the values in the context manager if the mocks are already provided - only if you use the automatic creation of mocks using DEFAULT.

If you need to access the mocks in your tests, you can use DEFAULT and adapt the mocks after they are created:

from unittest.mock import patch, DEFAULT

@pytest.fixture(scope='function', autouse=True)
def client_mock():    
    with patch.multiple(api_client,
                        method1=DEFAULT,
                        method2=DEFAULT,
                        method3=DEFAULT) as mocks:
        mocks['method1'].return_value = fixture1
        mocks['method2'].return_value = fixture2
        mocks['method3'].return_value = fixture3

        yield mocks

or you can construct the mocks beforehand and create the returned dictionary yourself:

@pytest.fixture(scope='function', autouse=True)
def client_mock():
    mock1 = MagicMock(return_value=fixture1)
    mock2 = MagicMock(return_value=fixture2)
    mock3 = MagicMock(return_value=fixture3)
    with patch.multiple(api_client,
                        method1=mock1,
                        method2=mock2,
                        method3=mock3):
        yield {'method1': mock1, 'method2': mock2, 'method3': mock3}

The usual case is probably that you just want to patch the objects and don't need to access them in the tests. In this case you can just use:

@pytest.fixture(scope='function', autouse=True)
def client_mock(request):    
    with patch.multiple(api_client,
                        method1=MagicMock(return_value=fixture1),
                        method2=MagicMock(return_value=fixture2),
                        method3=MagicMock(return_value=fixture3)):
        yield

I agree that the documentation for this is not very clear, so that it may cause such misunderstandings.

like image 108
MrBean Bremen Avatar answered Oct 30 '25 21:10

MrBean Bremen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!