I have a @memoize
decorator in my models, which caches some details on the model itself, to avoid multiple database calls when called many times (especially in templates). However, since I store the objects and refer to them in tests, this breaks things.
For example, if I do mygroup.subscribers
, add a subscriber and try it again, it will return an incorrect number of subscribers, since it's been memoized.
How can I monkey-patch that decorator to do nothing from my tests.py? I haven't found a way to do it cleanly, since models get loaded first.
At the beginning of memoize
implementation, checks if it is in testing mode as per this answer:
from django.core import mail
# at the beginning of your memoize
if hasattr(mail, 'outbox'):
# return without memorizing
You can disable your decorator in your test runner, the test environment will be set up before models are loaded.
For example:
from django.test.simple import DjangoTestSuiteRunner
from utils import decorators
class PatchTestSuiteRunner(DjangoTestSuiteRunner):
def setup_test_environment(self, **kwargs):
super(PatchTestSuiteRunner, self).setup_test_environment(**kwargs)
self.__orig_memoize = decorators.memoize
decorators.memoize = lambda x: x
def teardown_test_environment(self, **kwargs):
decorators.memoize = self.__orig_memoize
super(PatchTestSuiteRunner, self).teardown_test_environment(**kwargs)
Then put in your settings.py
:
TEST_RUNNER = 'test.PatchTestSuiteRunner'
And the tests can be run without memoization:
# myapp/models.py
class TestObject(object):
def __init__(self, value):
self.value = value
@memoize
def get_value(self):
return self.value
# myapp/test.py
from django.test import TestCase
from .models import TestObject
class NoMemoizeTestCase(TestCase):
def test_memoize(self):
t = TestObject(0)
self.assertEqual(t.get_value(), 0)
t.value = 1
self.assertEqual(t.get_value(), 1)
Note that although we're restoring the original decorator in the test runner's teardown_test_environment
, memoization will not be restored on already decorated functions. Memoization could be restored if we use a more complex testing decorator, but this is probably not required in standard use cases.
来源:https://stackoverflow.com/questions/14023763/how-can-i-monkey-patch-a-decorator-in-djangos-models-while-testing