A mnemonic for mock decorators

Using both @mock.patch decorators and py.test fixtures can be confusing as it’s not always clear what order arguments are being injected.

For instance, which of these is right? This:

@mock.patch.object(module, 'collaborator_1')
@mock.patch.object(module, 'collaborator_2')
def test_something_in_module(collaborator_1, collaborator_2, some_pytest_fixture):
    pass

Or this?

@mock.patch.object(module, 'collaborator_2')
@mock.patch.object(module, 'collaborator_1')
def test_something_in_module(collaborator_1, collaborator_2, some_pytest_fixture):
    pass

Or this?

@mock.patch.object(module, 'collaborator_2')
@mock.patch.object(module, 'collaborator_1')
def test_something_in_module(some_pytest_fixture, collaborator_1, collaborator_2):
    pass

I’ve wasted considerable time using PDB to work out what is being injected where.

Not any more though. Here’s how I remember:

  • The py.test fixtures always go at the end of the argument list. Their order doesn’t matter.

  • The @mock.patch decorators inject arguments sequentially so the inner decorator injects the first argument, then the next outer decorator injects the second argument and so on. Like this:

@mock.patch.object(module, 'collaborator_3')
@mock.patch.object(module, 'collaborator_2')
@mock.patch.object(module, 'collaborator_1')
def test_something_in_module(collaborator_1, collaborator_2, collaborator_3):
    pass

The things to remember is that it’s a symmetrical arrangement with the test function or method in the centre.

So the correct arrangement above is:

@mock.patch.object(module, 'collaborator_2')
@mock.patch.object(module, 'collaborator_1')
def test_something_in_module(collaborator_1, collaborator_2, some_pytest_fixture):
    pass

Postscript: The pytest-mock plugin can mitigate the confusion described above by providing the mock module as a pytest fixture - thanks to Floris Bruynooghe for pointing this out.
——————

Something wrong? Suggest an improvement or add a comment (see article history)
Tagged with: python, testing
Filed in: tips

Previous: Your codebase is your house
Next: Using pgbadger with AWS RDS

Copyright © 2005-2024 David Winterbottom
Content licensed under CC BY-NC-SA 4.0.