How can I monkey-patch a decorator in Django's models while testing?

可紊 提交于 2019-12-08 07:04:56

问题


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.


回答1:


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



回答2:


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!