2010-02-16 28 views
6

Ho definito alcuni timestamp per gli eventi nel database come auto_now_add, poiché le informazioni devono essere memorizzate con la data e l'ora nello stesso momento in cui è archiviato l'evento.Sovrascrivi auto_now per unittest

La descrizione degli eventi è qualcosa di simile

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

Per testare il modulo, sto generando alcune informazioni nel database nel file test.py, in questo modo:

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() 

devo generare eventi con il timestamp di ieri (il modulo li riepiloga quindi). Il problema è che non puoi sovrascrivere il timestamp. Il timestamp è quello in cui viene prodotto l'evento, lo documentation lo afferma in modo molto chiaro.

Quindi, come generare dati con timestamp appropriati per il test? Ho avuto diverse idee:

  • Forse generare i dati del database in un modo diverso, al di fuori delle classi del modello. Dove e come?
  • In qualche modo definire una classe differente o modificare la classe di comportarsi in modo diverso durante il test, qualcosa di simile a

_

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

O forse c'è un modo ancora più semplice per fare questo ... Tutte le idee?

+1

In merito a 'timestamp = models.DateTimeField (auto_now_add = testing)' come semplificazione? –

+0

La variabile 'testing' sarà True se test? Sarà fantastico, ma in questo caso dovrebbe essere qualcosa come "auto_now_add = non testing", penso ... – Khelben

+0

È la tua domanda e il tuo esempio, sentiti libero di risolverlo. –

risposta

2

Sono riuscito a creare dati che sostituiscono i valori predefiniti utilizzando un dispositivo.

ho creato un file test_data.json con i dati nel seguente formato:

[ 
{ 
    "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" 
    } 
}, 
... 

e quindi aggiungere al gruppo di test

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

+1: regola Fixtures. –

+2

Le partite non governano, hanno seri problemi. Usa [Fabbriche] (http://factoryboy.readthedocs.org/en/latest/orms.html) – SColvin

2

Il problema con i dispositivi per me, è che io è necessario testare che alcuni record che hanno più di 30 giorni non vengano restituiti, e quelli che non hanno 30 giorni di vita vengono restituiti ... usando dispositivi fissi questo non può essere fatto (in modo pigro). Quindi, quello che ho scelto di fare è prendere in giro la funzione timezone.now che django usa per ottenere il datetime da usare.

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 ... 

per beffardo Io uso minimocktest

+0

faking datetime è un'opzione molto migliore: http://tech.yunojuno.com/mocking-dates-with-django – SColvin

1

Un altro modo di gestire questo è quello di utilizzare un QuerySet update dopo l'istanza viene creato che può essere più utile a seconda del caso d'uso.

Poiché una chiamata update viene eseguita a livello SQL, salterà la convalida, i segnali e la funzionalità di salvataggio personalizzata. Richiederà una chiamata al database secondario che può influire sulle prestazioni, quindi dovrebbe essere utilizzata con attenzione.

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)