Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save burkestar/39e2f0f0e6090dd8760d to your computer and use it in GitHub Desktop.

Select an option

Save burkestar/39e2f0f0e6090dd8760d to your computer and use it in GitHub Desktop.
pytest test class that works with pytest fixtures and has some magic for scaffolding patchers that are reused across all class test methods
from collections import OrderedDict
import pytest
class MagicalPatchersMixin(object):
"""
A mixin for pytest xunit-style classes that provides scaffolding for setting up
patchers more easily that are setup for each class test method.
Additionally, a corresponding mock instance is created for each patch and attached to
the instance of the class. The naming of the mock is done by convention like the following:
self.create_patcher('some.sample_module.sample_method')
will create self.mock_sample_method with snake_case.
self.create_patcher('some.sample_module.SampleClass')
will create self.MockSampleClass with CamelCase
The mixin ensures the patchers are stopped during teardown of each method.
"""
def create_patcher(self, target):
self.patchers[target] = patch(target)
mock = self.patchers[target].start()
import importlib
import types
module_parts = target.split('.')
if len(module_parts) > 1:
target_module = importlib.import_module(".".join(module_parts[:-1]))
target_obj = module_parts[-1]
if type(target_module.__dict__[target_obj]) in [types.ClassType, types.TypeType, types.ObjectType]:
# CamelCase - assume target_obj is already CamelCase
setattr(self, 'Mock{}'.format(target_obj), mock)
else:
# snake_case - assume target_obj is already snake_case
setattr(self, 'mock_{}'.format(target_obj), mock)
return mock
def setup_method(self, method):
self.patchers = OrderedDict()
def teardown_method(self, method):
for patcher in self.patchers.itervalues():
if patcher:
patcher.stop()
@pytest.fixture
def some_fixture():
return {
'some': 'data'
}
class TestRun(MagicalPatchersMixin):
def setup_method(self, method):
super(TestRun, self).setup_method(method)
for p in ['some.sample_module.sample_method',
'some.sample_module.SampleClass']:
self.create_patcher(p)
def setup_class(self):
# fixtures
self.some_fixture = some_fixture()
def teardown_method(self, method):
super(TestRun, self).teardown_method(method)
def test_some_things(self):
assert type(self.some_fixture) == dict
self.mock_sample_method.return_value = 3
from some.sample_module import sample_method
assert sample_method("1234") == 3
self.mock_sample_method.assert_called_with("1234")
from some.sample_module import SampleClass
c = SampleClass(value=True)
self.MockClass.assert_called_with(value=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment