Search code examples
pythonunit-testingmonkeypatching

Monkeypatch persisting across unit tests python


I have a custom framework which runs different code for different clients. I have monkeypatched certain methods in order to customize functionality for a client.

Here is the pattern simplified:

    #import monkeypatches here
    if self.config['client'] == 'cool_dudes':
        from app.monkeypatches import Stuff
    if self.config['client'] == 'cool_dudettes':
        from app.monkeypatches import OtherStuff

Here is an example patch:

from app.framework.stuff import Stuff

def function_override(self):
  return pass

Stuff.function = function_override

This works fine when the program executes as it is executed in a batch manner, spinning up from scratch every time. However, when running across unit tests, I find that the monkey patches persist across tests, causing unexpected behavior.

I realize that it would be far better to use an object oriented inheritance approach to these overrides, but I inherited this codebase and am not currently empowered to rearchitect it to that degree.

Barring properly re-architecting the program, how can I prevent these monkey patches from persisting across unit tests?


Solution

  • The modules, including app.framework.<whatever>, are not reloaded for every test. So, any changes in them you make persist. The same happens if your module is stateful (that's one of the reasons why global state is not such a good idea, you should rather keep state in objects).

    Your options are to:

    • undo the monkey-patches when needed, or
    • change them into something more generic that would change (semi-)automatically depending on the test running, or
    • (preferred) Do not reinvent the wheel and use an existing, manageable, time-proven solution for your task (or at least, base your work on one if it doesn't meet your requirements completely). E.g. if you use them for mocking, see How can one mock/stub python module like urllib . Among the suggestions there is @mock.patch that does the patching for a specific test and undoes it upon its completion.