【问题标题】:Running unit tests in Python with a caching decorator使用缓存装饰器在 Python 中运行单元测试
【发布时间】:2015-03-10 20:54:06
【问题描述】:

所以我正在开发一个应用程序,该应用程序在导入某些记录时需要重新计算某些字段。为了防止每次检查都读取数据库,有一个缓存装饰器,因此在导入期间每 n 秒只执行一次数据库读取。问题在于构建测试用例。以下确实有效,但其中有一个丑陋的睡眠。

# The decorator I need to patch

@cache_function_call(2.0)
def _latest_term_modified():
    return PrimaryTerm.objects.latest('object_modified').object_modified


# The 2.0 sets the TTL of the decorator. So I need to switch out 
# self.ttl for this decorated function before 
# this test. Right now I'm just using a sleep, which works

    @mock.patch.object(models.Student, 'update_anniversary')
    def test_import_on_term_update(self, mock_update):
        self._import_student()
        latest_term = self._latest_term_mod()
        latest_term.save()
        time.sleep(3)
        self._import_student()
        self.assertEqual(mock_update.call_count, 2)

装饰器本身如下所示:

class cache_function_call(object):
    """Cache an argument-less function call for 'ttl' seconds."""
    def __init__(self, ttl):
        self.cached_result = None
        self.timestamp = 0
        self.ttl = ttl

    def __call__(self, func):
        @wraps(func)
        def inner():
            now = time.time()
            if now > self.timestamp + self.ttl:
                self.cached_result = func()
                self.timestamp = now
            return self.cached_result
        return inner

我尝试在导入模型之前设置装饰器:

decorators.cache_function_call = lambda x : x
import models

但即使在文件的顶部,django 仍然在运行我的 tests.py 之前初始化模型,并且该函数仍然使用缓存装饰器而不是我的 lambda/noop 装饰器进行装饰。

写这个测试的最好方法是什么,这样我就不用睡觉了。我可以在以某种方式运行我的导入之前设置装饰器的 ttl 吗?

【问题讨论】:

    标签: python django unit-testing caching django-models


    【解决方案1】:

    你可以稍微改变一下装饰器类。

    decorators.py 的模块级别设置全局

    BAILOUT = False
    

    在你的装饰器类中,改变:

    def __call__(self, func):
        @wraps(func)
        def inner():
            now = time.time()
            if BAILOUT or now > self.timestamp + self.ttl:
                self.cached_result = func()
                self.timestamp = now
            return self.cached_result
        return inner
    

    然后在你的测试集中decorators.BAILOUT = True,然后,嘿!-)

    【讨论】:

      猜你喜欢
      • 2017-08-20
      • 1970-01-01
      • 2012-04-26
      • 2016-08-20
      • 2015-09-02
      • 1970-01-01
      • 2016-12-30
      • 2015-07-29
      • 2013-03-19
      相关资源
      最近更新 更多