2010-02-16 10 views
6

J'ai défini certains horodatages pour les événements dans la base de données comme auto_now_add, car les informations doivent être stockées avec leur horodatage en même temps que l'événement est stocké.Remplacer auto_now pour unittest

La description des événements est quelque chose comme

class NewEvent(models.Model): 
    ''' 
    Individual event 
    ''' 
    name = models.CharField(max_length=100) 
    quantity = models.FloatField(null=True) 
    timestamp = models.DateTimeField(auto_now_add=True) 

Pour tester le module, je générer des informations dans la base de données dans le fichier test.py, de cette façon:

for event in EVENT_TYPES: 
     time = datetime.datetime.now() - datetime.timedelta(days=1) 
     for i in range(48): 
      time = time.replace(hour=i/2) 
      NewEvent(name=event, 
        timestamp=time, 
        quantity=i).save() 

je dois générer des événements avec son horodatage d'hier (le module les résumera ensuite). Le problème est que vous ne pouvez pas remplacer l'horodatage. L'horodatage c'est celui où l'événement est produit, le documentation le dit très clairement. Alors, comment générer des données avec des horodatages appropriés pour le test? J'ai eu plusieurs idées:

  • Peut-être générer les données de base de données d'une manière différente, en dehors des classes de modèle. Ou et comment?
  • définissent une certaine façon une autre classe ou changer la classe à se comporter différemment au cours du test, quelque chose comme

_

if testing: 
    timestamp = models.DateTimeField(auto_now_add=True) 
else: 
    timestamp = models.DateTimeField(auto_now_add=False) 

Ou peut-être il y a une encore plus facile de le faire ... Des idées?

+1

Que diriez-vous de 'timestamp = models.DateTimeField (auto_now_add = testing)' par simplification? –

+0

La variable 'testing' sera True si elle est testée? Ce sera génial, mais dans ce cas, ça devrait être quelque chose comme 'auto_now_add = ne pas tester ', je pense ... – Khelben

+0

C'est votre question et votre exemple, n'hésitez pas à le réparer. –

Répondre

2

J'ai réussi à créer des données remplaçant les valeurs par défaut à l'aide d'un appareil.

J'ai créé un fichier test_data.json avec les données dans le format suivant:

[ 
{ 
    "model": "stats_agg.newevent", 
    "pk": 1, 
    "fields": { 
     "name": "event1", 
     "quantity":0.0, 
     "timestamp": "2010-02-15 00:27:40" 
    } 
}, 
{ 
    "model": "stats_agg.newevent", 
    "pk": 2, 
    "fields": { 
     "name": "event1", 
     "quantity":1.0, 
     "timestamp": "2010-02-15 00:27:40" 
    } 
}, 
... 

puis ajouter à l'unité de test

class SimpleTest(TestCase): 
    fixtures = ['test_data.json'] 
+1

+1: Règle des appareils. –

+2

Les luminaires ne sont pas obligatoires, ils ont de sérieux problèmes. Utilisez [Factories] (http://factoryboy.readthedocs.org/en/latest/orms.html) – SColvin

2

Le problème avec les appareils pour moi, est que je besoin de tester que certains enregistrements de plus de 30 jours ne sont pas retournés, et que ceux qui ne datent pas de 30 jours sont retournés ... en utilisant des fixations statiques cela ne peut pas être fait (de manière paresseuse). Donc ce que j'ai choisi de faire est de mocker la fonction timezone.now que django utilise pour obtenir le datetime à utiliser.

from django.utils import timezone 

class SomeTestCase(TestCase): 
    def test_auto_add(self): 
     now = timezone.now() 
     now_31 = now - datetime.timedelta(days=31) 
     self.mock('timezone.now', returns=now_31, tracker=None) 
     SomeObject.objects.create() # has auto_now_add field ... 

pour se moquant J'utilise minimocktest

+0

truquer datetime est bien meilleure option: http://tech.yunojuno.com/mocking-dates-with-django – SColvin

1

Une autre façon de traiter est d'utiliser un QuerySet update après l'instance est créé qui peut être plus utile en fonction de votre cas d'utilisation.

Lorsqu'un appel update est effectué au niveau SQL, il ignore la validation, les signaux et les fonctions d'enregistrement personnalisées. Cela nécessitera un appel de base de données secondaire qui peut avoir un impact sur les performances et devrait donc être utilisé avec considération.

for event in EVENT_TYPES: 
    time = datetime.datetime.now() - datetime.timedelta(days=1) 
    for i in range(48): 
     time = time.replace(hour=i/2) 
     instance = NewEvent(name=event, quantity=i).save() 
     NewEvent.objects.filter(pk=instance.pk).update(timestamp=time) 
Questions connexes