【问题标题】:How can I monkey-patch a decorator in Django's models while testing?如何在测试时对 Django 模型中的装饰器进行猴子修补?
【发布时间】:2012-12-11 00:26:39
【问题描述】:

我的模型中有一个@memoize 装饰器,它缓存了模型本身的一些细节,以避免在多次调用时(尤其是在模板中)多次调用数据库。但是,由于我存储对象并在测试中引用它们,这会破坏事情。

例如,如果我做mygroup.subscribers,添加一个订阅者然后再试一次,它会返回不正确的订阅者数量,因为它已被记忆。

如何在我的 tests.py 中对装饰器进行猴子修补以不执行任何操作?我还没有找到干净的方法,因为模型首先加载。

【问题讨论】:

    标签: python django testing monkeypatching


    【解决方案1】:

    您可以在test runner 中禁用您的装饰器,测试环境将在模型加载之前设置。

    例如:

    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)
    

    然后输入你的settings.py:

    TEST_RUNNER = 'test.PatchTestSuiteRunner'
    

    并且测试可以在没有记忆的情况下运行:

    # 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)
    

    请注意,尽管我们正在恢复测试运行器的 teardown_test_environment 中的原始装饰器,但不会在已装饰的函数上恢复记忆。如果我们使用更复杂的测试装饰器,可以恢复记忆,但这在标准用例中可能不是必需的。

    【讨论】:

      【解决方案2】:

      memoize 实现开始时,根据answer 检查它是否处于测试模式:

      from django.core import mail
      
      # at the beginning of your memoize
      if hasattr(mail, 'outbox'):
          # return without memorizing
      

      【讨论】:

      • 我宁愿避免在那里添加测试代码,因为我想继续测试包含在我的tests.py中的代码。不过,谢谢您的回答!
      猜你喜欢
      • 2023-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多