2010-02-15 13 views
22

Estoy intentando crear pruebas para algunos modelos que tienen un FileField. El modelo es el siguiente:Prueba de Django FileField usando dispositivos de prueba

class SolutionFile(models.Model): 
    ''' 
    A file from a solution. 
    ''' 
    solution = models.ForeignKey(Solution) 
    file = models.FileField(upload_to=make_solution_file_path) 

me he encontrado con dos problemas:

  1. Al guardar datos a un dispositivo usando ./manage.py dumpdata, el contenido del archivo no se guardan, sólo el nombre de archivo se guarda en el accesorio. Aunque considero que este es el comportamiento esperado, ya que los contenidos del archivo no se guardan en la base de datos, me gustaría incluir esta información de alguna manera en el dispositivo para realizar pruebas.

  2. Tengo un caso de prueba para subir un archivo que tiene el siguiente aspecto:

    def test_post_solution_file(self): 
        import tempfile 
        import os 
        filename = tempfile.mkstemp()[1] 
        f = open(filename, 'w') 
        f.write('These are the file contents') 
        f.close() 
        f = open(filename, 'r') 
        post_data = {'file': f} 
        response = self.client.post(self.solution.get_absolute_url()+'add_solution_file/', post_data, 
               follow=True) 
        f.close() 
        os.remove(filename) 
        self.assertTemplateUsed(response, 'tests/solution_detail.html') 
        self.assertContains(response, os.path.basename(filename)) 
    

Si bien esta prueba funciona bien, deja el archivo cargado en el directorio de los medios de comunicación después de terminar. Por supuesto, la eliminación podría resolverse en tearDown(), pero me preguntaba si Django tenía otra forma de lidiar con esto.

Una solución en la que estaba pensando era utilizar una carpeta de medios diferente para las pruebas que deben mantenerse sincronizadas con los dispositivos de prueba. ¿Hay alguna manera de especificar otro directorio de medios en settings.py cuando se están ejecutando las pruebas? ¿Y puedo incluir algún tipo de hook a dumpdata para que sincronice los archivos en las carpetas multimedia?

Entonces, ¿hay alguna forma más Pythonic o específica de Django para manejar las pruebas unitarias que involucran archivos?

+0

Así os.remove (foo) does't de trabajo? ¿Lanza una excepción? Tal vez no haya los privilegios correctos en ese directorio/archivo para poder eliminarlo desde dentro de su unidad de prueba? –

+0

El 'os.remove() 'parte en el código elimina el archivo del directorio temporal. Para eliminar el archivo cargado, tendría que buscar en el directorio de medios y seguir una lógica más complicada para encontrar la ubicación exacta del archivo. Estoy buscando una forma más fácil y automatizada para hacerlo, si es que existe. – sttwister

+1

D'oh, lo siento! Leí mal tu publicación. ¿Qué hay de la configuración de hackeo.MEDIA_ROOT = '/ path/to/project/static/y/then/alternative/storage /' y settings.MEDIA_URL = '/ static/y/then/alternative/storage /' en su setUp para sus pruebas ? Hacky, pero podría hacer el trabajo ... –

Respuesta

17

Django proporciona una gran manera de escribir pruebas en FileFields sin curioseaba en el sistema de archivos real, - utilizar un SimpleUploadedFile.

from django.core.files.uploadedfile import SimpleUploadedFile 

my_model.file_field = SimpleUploadedFile('best_file_eva.txt', 'these are the file contents!') 

Es una de las características-que-no-show-up-en-el-docs mágicos de Django :). Sin embargo, se hace referencia al here.

+3

Los contenidos no binarios provocan un error en Python 3+; puedes arreglar eso simplemente haciendo que los contenidos sean binarios, como lo hacen: 'my_model.file_field = SimpleUploadedFile ('best_file_eva.txt', b'these is the file contents! ')' – LaundroMat

3

He escrito pruebas unitarias para una aplicación de galería completa antes, y lo que funcionó bien para mí fue utilizar los módulos tempfile y shutil de python para crear copias de los archivos de prueba en directorios temporales y luego eliminarlos todos después.

El siguiente ejemplo no está funcionando/completa, pero se debe obtener en el camino correcto:

import os, shutil, tempfile 

PATH_TEMP = tempfile.mkdtemp(dir=os.path.join(MY_PATH, 'temp')) 

def make_objects(): 
    filenames = os.listdir(TEST_FILES_DIR) 

    if not os.access(PATH_TEMP, os.F_OK): 
     os.makedirs(PATH_TEMP) 

    for filename in filenames: 
     name, extension = os.path.splitext(filename) 
     new = os.path.join(PATH_TEMP, filename) 
     shutil.copyfile(os.path.join(TEST_FILES_DIR, filename), new) 

     #Do something with the files/FileField here 

def remove_objects(): 
    shutil.rmtree(PATH_TEMP) 

corro esos métodos en el setup() y tearDown() de mis pruebas de unidad y funciona ¡estupendo! Tienes una copia limpia de tus archivos para probar tu campo de archivos que son reutilizables y predecibles.

+0

No veo cómo eso puede ayudarme. Quiero sobrescribir el directorio de medios de Django con uno de prueba. Y también quiero exportar/copiar de alguna manera los archivos cuando utilizo './manage.py dumpdata'. – sttwister

+0

Sobrescribir el directorio de medios de django es una mala idea. A menos que mueva el directorio de medios actual a otro lugar y lo vuelva a colocar posteriormente, nunca podrá ejecutar pruebas en su sitio en vivo porque será una operación destructiva. Usted * podría * mover la carpeta de medios y volver a colocarla utilizando los compartimentos como sugerí anteriormente. Más allá de eso, dumpdata nunca exportará archivos por usted. Deberá escribir su propia secuencia de comandos o manage.py para eso. –

0

Esto es lo que hice para mi prueba. Después de cargar el archivo debe terminar en el inmueble imagen de mi modelo objeto organización:

import tempfile 
    filename = tempfile.mkstemp()[1] 
    f = open(filename, 'w') 
    f.write('These are the file contents') 
    f.close() 
    f = open(filename, 'r') 
    post_data = {'file': f} 
    response = self.client.post("/org/%d/photo" % new_org_data["id"], post_data) 
    f.close() 
    self.assertEqual(response.status_code, 200) 

    ## Check the file 
    ## org is where the file should end up 
    org = models.Organization.objects.get(pk=new_org_data["id"]) 
    self.assertEqual("These are the file contents", org.photo.file.read()) 

    ## Remove the file 
    import os 
    os.remove(org.photo.path) 
5

Puede anular la configuración MEDIA_ROOT para sus pruebas con el decorador @override_settings()as documented:

from django.test import override_settings 


@override_settings(MEDIA_ROOT='/tmp/django_test') 
def test_post_solution_file(self): 
    # your code here 
Cuestiones relacionadas