2010-02-16 7 views
6

He definido algunas marcas de tiempo para eventos en la base de datos como auto_now_add, ya que la información debe almacenarse con su marca de tiempo al mismo tiempo que se almacena el evento.Sobrescribir auto_now para unittest

La descripción de los hechos es algo así como

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

Para probar el módulo, estoy generando alguna información en la base de datos en el archivo test.py, de esta manera:

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

debo generar eventos con su marca de tiempo de ayer (el módulo los resumirá). El problema es que no puede sobrescribir la marca de tiempo. La marca de tiempo es la indicada cuando se produce el evento, el documentation lo dice muy claramente.

Entonces, ¿cómo generar datos con las marcas de tiempo apropiadas para la prueba? He tenido varias ideas:

  • Quizás genere los datos de la base de datos de una manera diferente, fuera de las clases del modelo. ¿Dónde y cómo?
  • definen alguna manera una clase diferente o cambiar la clase a comportarse de manera diferente durante la prueba, algo así como

_

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

O tal vez hay una manera más fácil de hacer esto ... ¿Alguna idea?

+1

¿Qué tal 'timestamp = models.DateTimeField (auto_now_add = testing)' como una simplificación? –

+0

'prueba 'variable será verdadero si las pruebas? Eso será genial, pero en este caso, debería ser algo así como 'auto_now_add = not testing', creo ... – Khelben

+0

Es su pregunta y su ejemplo, no dude en solucionarlo. –

Respuesta

2

He logrado crear datos anulando los valores predeterminados utilizando un dispositivo.

He creado un archivo test_data.json con los datos en el siguiente 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" 
    } 
}, 
... 

y luego añadir a la unidad de prueba

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

+1: regla de luminarias. –

+2

Los accesorios no gobiernan, tienen un problema serio. Utilice [Factories] (http://factoryboy.readthedocs.org/en/latest/orms.html) – SColvin

2

El problema con los accesorios para mí, es que me Es necesario probar que ciertos registros que tienen más de 30 días no se devuelven, y los que no tienen 30 días de antigüedad se devuelven ... utilizando accesorios estáticos esto no se puede hacer (de manera perezosa). Entonces, lo que elegí hacer fue burlarme de la función timezone.now que django usa para usar datetime.

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

por burlarse utilizo minimocktest

+0

falsificar la fecha y hora es una opción mucho mejor: http://tech.yunojuno.com/mocking-dates-with-django – SColvin

1

Otra manera de manejar esto es usar un QuerySet update después de que la instancia se crea que puede ser más útil dependiendo de su caso de uso.

Como se realiza una llamada update en el nivel SQL, omitirá la validación, las señales y la funcionalidad de guardar personalizada. Se requerirá una llamada de base de datos secundaria que puede afectar el rendimiento por lo que debe utilizarse con consideración.

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)