2017-02-01 69 views
5

我在这里写一个功能测试,以检查我的API节流是否按预期工作(将在每个月初休息)。django测试中的嘲笑时间问题:时间似乎不会被freezegun冻结

测试类:

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) 

测试工作正常,如果:last_day_of_current_month = datetime.datetime(... second=0)
但如果将失败:last_day_of_current_month = datetime.datetime(... second=59)

调试后,这似乎是在DjangoRestFramework throttling.UserRateThrottle使用的time模块总是在某种程度上给我一个始终超过我的测试时间的价值,这是ca使用几秒钟的精确度问题。

基于FreezeGun Doctime.time()也应该是冰冻:

Once the decorator or context manager have been invoked, all calls to datetime.datetime.now(), datetime.datetime.utcnow(), datetime.date.today(), time.time(), time.localtime(), time.gmtime(), and time.strftime() will return the time that has been frozen.

但它看起来像IM我的情况time.time采取正确的嘲笑日期时间的开始时间,但随后不断变化,在其上不预期时间,它的预期被冻结,直到手动转发时间。

我试图模拟time.time使用在UserRateThrottle分别使用mock模块,但仍然没有解决问题。

---->任何想法可能是什么问题,以及如何可能解决?

测试失败:(后时间被转发给该月的最后一天:线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 
     .... 

回答

0

您需要用FreezeG覆盖SimpleRateThrottle的计时器联合国的时间。

这里发生的事情是,feezegun可能覆盖Python的时间模块。然而,SimpleRateThrottle不使用该模块,它使用模块的功能,它成为冻枪的范围。

SimpleRateThrottle因此使用Python标准库时间模块,而其他部分代码使用freezegun的一个。

编辑: 你应该做的 - FreezeGun激活后:

former_timer = SimpleRateThrottle.timer 
SimpleRateThrottle.timer = time.time 

,一旦测试结束(在拆卸或任何等价物):

SimpleRateThrottle.timer = former_timer 

注意可以也可以使用猴子补丁库来为你处理。

+0

如何用FreezeGun覆盖它!?实际上,我考虑过这个问题,并尝试使用python mock模块手动使用猴子修补来模拟SimpleRateThrottle使用的模块函数的返回值,但仍然存在相同的问题! – DhiaTN

+1

对不起,意识到我写了我的答案后。现在编辑一个如何。 – Linovia

+0

谢谢,但仍然有同样的问题。 – DhiaTN