Dhi*_*aTN 6 python django unit-testing django-rest-framework freezegun
我在这里写一个功能测试来检查我的API限制是否按预期工作(将在每个月的开始时休息).
测试类:
class ApiThrottlingTest(ThrottlingBaseTest):
def test_throttling_purchaser_case(self):
now = datetime.datetime(year=2015, month=1, day=10, hour=6, minute=6, second=3)
last_day_of_current_month = datetime.datetime(year=2015, month=1, day=31, hour=23, minute=59, second=59)
first_day_of_next_month = datetime.datetime(year=2015, month=2, day=1, hour=0, minute=0, second=0)
with freeze_time(now) as frozen_datetime:
for i in xrange(3):
resp = self._project_details_request()
self.assertEqual(resp.status_code, 200)
resp = self._project_details_request()
self.assertEqual(resp.status_code, 429)
frozen_datetime.move_to(last_day_of_current_month)
resp = self._project_details_request()
# the test fails at this level
self.assertEqual(resp.status_code, 429)
frozen_datetime.move_to(first_day_of_next_month)
resp = self._project_details_request()
self.assertEqual(resp.status_code, 200)
Run Code Online (Sandbox Code Playgroud)
如果出现以下情况,测试工作正常:last_day_of_current_month = datetime.datetime(... second=0)
但如果出现以last_day_of_current_month = datetime.datetime(... second=59)
在调试之后,似乎timeDjangoRestFramework throttling.UserRateThrottle中使用的模块在某种程度上给出了一个值,该值总是超过我测试中的前一个时间,这导致了几秒钟的精度问题.
基于FreezeGun Doc time.time()也应冻结:
一旦调用了装饰器或上下文管理器,所有调用datetime.datetime.now(),datetime.datetime.utcnow(),datetime.date.today(),time.time(),time.localtime(),time .gmtime()和time.strftime()将返回已冻结的时间.
但看起来我的情况time.time正确地取得了模拟日期时间的开始时间,但随后随着时间的推移不断变化,这是预期的,它会被冻结,直到手动转发时间.
我试图使用模块单独使用模拟time.time,但仍然没有解决问题.UserRateThrottlemock
---->任何想法可能是什么问题,怎么可能解决?
测试失败:(在时间转发到该月的最后一天之后:第14行)
self.assertEqual(resp.status_code,429)
AssertionError:200!= 429
DRF类源代码:
class SimpleRateThrottle(BaseThrottle):
...
cache = default_cache
timer = time.time
cache_format = 'throttle_%(scope)s_%(ident)s'
def __init__(self):
....
def allow_request(self, request, view):
...
self.now = self.timer() # here timer() returns unexpected value in test
....
Run Code Online (Sandbox Code Playgroud)
你需要覆盖SimpleRateThrottle使用 FreezeGun 的 time.time 覆盖 的计时器。
这里发生的情况是,fezegun 可能会覆盖 Python 的时间模块。但是,SimpleRateThrottle不使用该模块,而是使用该模块的功能,而该模块的功能变得超出了冷冻枪的范围。
SimpleRateThrottle因此使用Python标准库时间模块,而代码的其他部分使用freezegun的时间模块。
编辑:您应该在 FreezeGun 激活后执行以下操作:
former_timer = SimpleRateThrottle.timer
SimpleRateThrottle.timer = time.time
Run Code Online (Sandbox Code Playgroud)
一旦你的测试结束(在拆解或其他类似的情况下):
SimpleRateThrottle.timer = former_timer
Run Code Online (Sandbox Code Playgroud)
请注意,您还可以使用猴子修补库来为您处理该问题。