5

J'écris ici un test fonctionnel pour vérifier si ma régulation de l'API fonctionne comme prévu (ce sera le repos au début de chaque mois).Problème de temps de moquerie dans le test django: le temps ne semble pas être gelé avec freezegun

Classe d'essai:

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) 

Le test fonctionne bien si: last_day_of_current_month = datetime.datetime(... second=0)
mais échouera si: last_day_of_current_month = datetime.datetime(... second=59)

Après le débogage, il semble que le module time utilisé dans DjangoRestFramework throttling.UserRateThrottle est en quelque sorte donner une valeur qui est toujours en avance sur le temps de fronzen dans mon test, qui est ca en utilisant un problème de précision de quelques secondes.

Basé sur FreezeGun Doctime.time() devrait aussi être congelés:

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.

Mais il semble que im mon cas time.time prend correctement l'heure de début de l'datetime moqué mais ne cessent de changer au fil du temps qui ne devrait pas, il est prévu être congelé jusqu'à ce que l'heure soit transmise manuellement.

J'ai essayé de simuler time.time utilisé dans UserRateThrottle séparément en utilisant mock module mais n'a pas encore résolu le problème.

----> Une idée de ce qui pourrait être le problème, et comment pourrait éventuellement être résolu?

test Fail: (après le temps est transmis au dernier jour du mois: ligne 14)

self.assertEqual(resp.status_code, 429)
AssertionError: 200 != 429

Le code source de la classe 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 
     .... 

Répondre

0

vous devrez remplacer le minuteur SimpleRateThrottle avec le FreezeG temps de l'ONU.

Qu'est-ce qui se passe ici est que feezegun probablement substituer le module de temps de Python. Cependant, SimpleRateThrottle n'utilise pas le module, il utilise la fonction du module qui devient hors de portée du pistolet de congélation.

SimpleRateThrottle utilise donc le module de temps de bibliothèque standard Python tandis que l'autre partie du code utilise celle de freezegun.

Edit: Vous devriez faire - après FreezeGun a été activé:

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

et une fois que votre test est terminé (dans le tearDown ou tout équivalent):

SimpleRateThrottle.timer = former_timer 

Notez que vous pouvez utilisez également un lib de patch de singe pour gérer cela pour vous.

+0

Comment puis-je le remplacer avec FreezeGun !? En fait, j'y ai pensé et j'ai essayé de me moquer de la valeur renvoyée de la fonction module utilisée par 'SimpleRateThrottle' manuellement en utilisant le patch de singe en utilisant le module python' mock' mais j'ai toujours le même problème !!! – DhiaTN

+1

désolé, s'est rendu compte qu'après avoir écrit ma réponse. Il est maintenant édité avec un comment. – Linovia

+0

Merci, mais ont toujours le même problème. – DhiaTN