pythontddpytestpython-mock

How to patch globally in pytest?


I use pytest quite a bit for my code. Sample code structure looks like this. The entire codebase is python-2.7

core/__init__.py
core/utils.py

#feature

core/feature/__init__.py
core/feature/service.py

#tests
core/feature/tests/__init__.py
core/feature/tests/test1.py
core/feature/tests/test2.py
core/feature/tests/test3.py
core/feature/tests/test4.py
core/feature/tests/test10.py

The service.py looks something like this:

from modules import stuff
from core.utils import Utility


class FeatureManager:
    # lots of other methods
    def execute(self, *args, **kwargs):
        self._execute_step1(*args, **kwargs)
        # some more code
        self._execute_step2(*args, **kwargs)
        utility = Utility()
        utility.doThings(args[0], kwargs['variable'])

All the tests in feature/tests/* end up using core.feature.service.FeatureManager.execute function. However utility.doThings() is not necessary for me to be run while I am running tests. I need it to happen while the production application runs but I do not want it to happen while the tests are being run.

I can do something like this in my core/feature/tests/test1.py

from mock import patch

class Test1:
   def test_1():
       with patch('core.feature.service.Utility') as MockedUtils:
           exectute_test_case_1()

This would work. However I added Utility just now to the code base and I have more than 300 test cases. I would not want to go into each test case and write this with statement.

I could write a conftest.py which sets a os level environment variable based on which the core.feature.service.FeatureManager.execute could decide to not execute the utility.doThings but I do not know if that is a clean solution to this issue.

I would appreciate if someone could help me with global patches to the entire session. I would like to do what I did with the with block above globally for the entire session. Any articles in this matter would be great too.

TLDR: How do I create session wide patches while running pytests?


Solution

  • I added a file called core/feature/conftest.py that looks like this

    import logging
    import pytest
    from unittest import mock
    
    
    @pytest.fixture(scope="session", autouse=True)
    def default_session_fixture(request):
        """
        :type request: _pytest.python.SubRequest
        :return:
        """
        log.info("Patching core.feature.service")
        patched = mock.patch('core.feature.service.Utility')
        patched.__enter__()
    
        def unpatch():
            patched.__exit__()
            log.info("Patching complete. Unpatching")
    
        request.addfinalizer(unpatch)
    

    This is nothing complicated. It is like doing

    with mock.patch('core.feature.service.Utility') as patched:
        do_things()
    

    but only in a session-wide manner.