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

霸气de小男生 提交于 2019-12-07 15:25:26
Thierry Lam

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.

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