2010-03-28 12 views
8

Me gustaría tener un módulo de Python que contenga algunas pruebas de unidad que puedo pasar al hg bisect --command.Cómo configurar y desmontar temporalmente django db para pruebas unitarias?

Las pruebas unitarias están probando algunas funciones de una aplicación de Django, pero no creo que pueda usar hg bisect --command manage.py test mytestapp porque mytestapp tendría que estar habilitadas en settings.py, y las ediciones en settings.py serían Demolí cuando hg bisect actualiza el directorio de trabajo.

Por lo tanto, me gustaría saber si algo como lo siguiente es el mejor camino a seguir:

import functools, os, sys, unittest 

sys.path.append(path_to_myproject) 
os.environ['DJANGO_SETTINGS_MODULE'] = 'myapp.settings' 


def with_test_db(func): 
    """Decorator to setup and teardown test db.""" 
    @functools.wraps 
    def wrapper(*args, **kwargs): 
     try: 
      # Set up temporary django db 
      func(*args, **kwargs) 
     finally: 
      # Tear down temporary django db 


class TestCase(unittest.TestCase): 

    @with_test_db 
    def test(self): 
     # Do some tests using the temporary django db 
     self.fail('Mark this revision as bad.') 


if '__main__' == __name__: 
    unittest.main() 

que debería estar más agradecido si pudiera aconsejar bien:

  1. Si hay de una manera más simple, tal vez subclasificando django.test.TestCase pero no editando settings.py o, si no;
  2. ¿Cuáles deberían ser las líneas anteriores que dicen "Configurar django db temporal" y "Desmontar django db temporal"?

Respuesta

8

Cracked it. Ahora tengo un archivo Python completamente independiente de cualquier aplicación Django que se puede ejecutar pruebas unitarias con una base de datos de prueba:

#!/usr/bin/env python 
"""Run a unit test and return result. 

This can be used with `hg bisect`. 
It is assumed that this file resides in the same dir as settings.py 

""" 

import os 
from os.path import abspath, dirname 
import sys 
import unittest 

# Set up django 
project_dir = abspath(dirname(dirname(__file__))) 
sys.path.insert(0, project_dir) 
os.environ['DJANGO_SETTINGS_MODULE'] = 'myproject.settings' 

from django.db import connection 
from django.test import TestCase 
from django.test.utils import setup_test_environment, teardown_test_environment 

from myproject import settings 
from myproject.myapp.models import MyModel 


class MyTestCase(TestCase): 

    def test_something(self): 
     # A failed assertion will make unittest.main() return non-zero 
     # which if used with `hg bisect` will mark the revision as bad 
     self.assertEqual(0, len(MyModel.objects.all())) # and so on 


if '__main__' == __name__: 
    try: 
     setup_test_environment() 
     settings.DEBUG = False  
     verbosity = 0 
     old_database_name = settings.DATABASE_NAME 
     connection.creation.create_test_db(verbosity) 
     unittest.main() 
    finally: 
     connection.creation.destroy_test_db(old_database_name, verbosity) 
     teardown_test_environment() 
+0

+1 para publicar la solución final. –

+0

Gracias. Espero que esto muestre a otros cómo configurar la base de datos de prueba de django para cualquier prueba unitaria arbitraria, incluidas las pruebas de nariz. – blokeley

5

Debe usar el Django TestCase interno para hacerlo.

from django.test import TestCase 

class TestCase(TestCase): 

    # before every call to setUp(), the db is automatically 
    # set back to the state is was after the first syncdb then 
    # all these fixture files will be loaded in the db 
    fixtures = ['mammals.json', 'birds'] 

    # put whatever you want here, you don't need to call the 
    # super() 
    def setUp(self): 
     # Test definitions as before. 
     call_setup_methods() 

    def test(self): 
     # Do some tests using the temporary django db 
     self.fail('Mark this revision as bad.') 

Es totalmente compatible con la prueba de unidad por lo que su código no necesita cambiar mucho.

Puede obtener más información sobre los comandos django.test, fixtures, flush y loaddata.

Si desea utilizar un decorador para hacer el trabajo, puede usar el call_command para usar en su programa python cualquier comando django. por ejemplo:

from django.core.management import call_command 

call_command('flush', 'myapp') 
call_command('loaddata', 'myapp') 
+0

Si pongo el código en un archivo llamado mytest.py, todavía no puede simplemente ejecutar 'python mytest.py' para ejecutar las pruebas unitarias, que es lo que necesito. – blokeley

+1

@blokeley: Tienes dos opciones obvias. Las pruebas entran en 'models.py' o entran en' tests.py'. Si usas 'tests.py' en lugar de' mytest.py', estarás contento. –