2017-02-01 97 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