Ben Murden

Archive for September, 2015

Django Test Mock Factory

by on Sep.29, 2015, under Development

There are many ways to use Python Mock’s patcher, but sometimes there’s something in your test module you’ll always need to mock. It’s possible to apply the patcher to the entire class, but it still means you have to litter your tests with parameters. To make things a bit tidier and DRYer, I started using the following mock factory in my tests to create instance-level mocks.

def add_mock(self, target, *args, **kwargs):
    target_obj = target.split('.')[-1]
    patcher = patch(target, *args, **kwargs)
    if target_obj[0].isupper():
        # Assume class mock
        attr = 'Mock'
    else:
        attr = 'mock_'

    attr += target_obj

    setattr(self, attr, patcher.start())
    self.addCleanup(patcher.stop)

The above attribute factory will add new instance level attributes, named either mock_some_variable for imports that look like variables or functions, or MockSomeObject for imports that look like objects. It will use the patcher’s patch function directly, and assign the new attribute to the current test object instance, then stop the patch at clean up.

This can be used in your tests’ setup method like so.

def setUp(self):
    module = 'my_app.management.commands.send_monthly_report'
    self.add_mock('%s.settings' % module)

    # Pass patch arguments through the setup method
    self.add_mock('%s.send_mail' % module, autospec=True)

    # We now have an instance-level mock to work with
    self.mock_settings.REPORT_TEMPLATE = 'test-template'

Now all your test methods have instance attributes to work with instead of a long line of parameters. Much better!

def test_the_first(self):
    function_to_test()
    self.assertTrue(self.mock_send_mail.called)
3 Comments :, , more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!