pythonpython-3.xunit-testingpytest

Reuse patch statements


I have these two statements repeating in many of my unit tests.

        with patch('/path') as mocked_thing1:
            mocked_thing1.return_value = 'some value'
            with patch('/path') as mocked_thing2:
                mocked_thing2.return_value = 'some value'

Is there a way I can write a function for it and just call it instead of writing these lines repeatedly in my test cases?


Solution

  • If you want to change the return value for different tests, you have no way but to assign the return value in each test. One way would be to add separate fixtures for the mocks:

    @pytest.fixture
    def mock_thing1():
        with patch('/path') as mocked_thing1:
            yield mocked_thing1
    
    @pytest.fixture
    def mock_thing2():
        with patch('/path') as mocked_thing2:
            yield mocked_thing2
    
    def test_something(mock_thing1, mock_thing2):
        mocked_thing1.return_value = 'some value'
        mocked_thing2.return_value = 'some value'
        ...
    

    Another possibility is to use indirect fixture parameters to set the return value in the fixture:

    @pytest.fixture
    def mock_thing1(request):
        with patch('/path') as mocked_thing1:
            mocked_thing1.return_value = request.param
            yield mocked_thing1
    
    @pytest.fixture
    def mock_thing2(request):
        with patch('/path') as mocked_thing2:
            mocked_thing2.return_value = request.param
            yield mocked_thing2
    
    
    @pytest.mark.parametrize("mock_thing2", ['some other value'], indirect=True)
    @pytest.mark.parametrize("mock_thing1", ['some value'], indirect=True)
    def test_something(mock_thing1, mock_thing2):
        ...
    

    Or you could just use the decorator version of patch instead of any fixture, so that at least the test body is better readable:

    @mock.patch("mock_thing2", return_value='some other value')
    @mock.patch("mock_thing1", return_value='some value')
    def test_something(mock_thing1, mock_thing2):
        ...