2010-02-15 18 views
22

Sto provando a costruire test per alcuni modelli che hanno un FileField. Il modello si presenta così:Test di Django FileField usando i dispositivi di prova

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

ho incontrato due problemi:

  1. Durante il salvataggio di dati in un apparecchio utilizzando ./manage.py dumpdata, il contenuto del file non vengono salvate, solo il nome del file viene salvato nella apparecchio. Mentre trovo questo comportamento atteso in quanto i contenuti del file non vengono salvati nel database, mi piacerebbe in qualche modo includere queste informazioni nella fixture per i test.

  2. Ho un banco di prova per il caricamento di un file che assomiglia a questo:

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

Mentre questo test funziona bene, lascia il file caricato nella directory dei media dopo la rifinitura. Naturalmente, la cancellazione potrebbe essere risolta in tearDown(), ma mi stavo chiedendo se Django avesse un altro modo di affrontare questo.

Una soluzione a cui stavo pensando stava utilizzando una cartella multimediale diversa per i test che devono essere sincronizzati con i dispositivi di prova. Esiste un modo per specificare un'altra directory multimediale in settings.py quando vengono eseguiti i test? E posso includere una sorta di hook per dumpdata in modo che sincronizzi i file nelle cartelle multimediali?

Quindi, c'è un modo più Pythonico o Django specifico per gestire i test unitari che riguardano i file?

+0

Così os.remove (foo) lavoro does't? Fa un'eccezione? Forse non ci sono i privilegi corretti su quella directory/file per poterlo eliminare dall'interno del test dell'unità? –

+0

Il 'os.remove() 'parte nel codice cancella il file dalla directory temp. Per eliminare il file caricato, dovrei cercare nella directory multimediale e seguire una logica più complicata per trovare la posizione esatta del file. Sto cercando un modo più semplice e automatico per farlo, se esiste anche. – sttwister

+1

D'oh, mi dispiace! Ho letto male il tuo post. Che ne dici delle impostazioni di hacking.MEDIA_ROOT = '/ percorso/a/progetto/statico/e/allora/alternativa/archiviazione /' e impostazioni.MEDIA_URL = '/ statico/e/poi/alternativa/archiviazione /' nel tuo setUp per i tuoi test ? Hacky, ma potrebbe fare il lavoro ... –

risposta

17

Django fornisce un ottimo modo per scrivere test su FileFields senza pasticciare in giro nel vero filesystem - utilizzare un SimpleUploadedFile.

from django.core.files.uploadedfile import SimpleUploadedFile 

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

E 'una delle caratteristiche-che-non-show-up-in-the-docs magici di Django :). Tuttavia si riferisce a here.

+3

I contenuti non binari generano un errore in Python 3+; puoi correggerlo semplicemente rendendo il contenuto binario, in questo modo: 'my_model.file_field = SimpleUploadedFile ('best_file_eva.txt', b 'questi sono i contenuti del file!')' – LaundroMat

3

Ho già scritto test di unità per un'intera app di galleria e ciò che ha funzionato bene è stato l'utilizzo dei moduli python tempfile e shutil per creare copie dei file di prova nelle directory temporanee e quindi eliminarli tutti in seguito.

L'esempio seguente non funziona/completo, ma dovrebbe ottenere sulla strada giusta:

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 tali metodi nel setup() e tearDown() metodi di mio test di unità e funziona grande! Hai una copia pulita dei tuoi file per testare il tuo file file che sono riutilizzabili e prevedibili.

+0

Non vedo come possa aiutarmi. Voglio sovrascrivere la directory dei media di Django con una versione di prova. E voglio anche esportare/copiare i file quando uso './manage.py dumpdata'. – sttwister

+0

La sovrascrittura della directory multimediale di django è una cattiva idea. A meno che non spostiate la directory multimediale corrente da qualche altra parte e la rimettiamo in seguito, non sarete mai in grado di eseguire test sul vostro sito live perché sarà un'operazione distruttiva. Si * potrebbe * spostare la cartella multimediale e rimetterla usando shutils come suggerito sopra. Oltre a questo, dumpdata non esporterà mai file per te. Dovrai scrivere il tuo script o l'estensione manage.py per quello. –

0

Questo è quello che ho fatto per il mio test. Dopo aver caricato il file dovrebbe finire nella foto di proprietà di mio oggetto modello organizzativo:

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

È possibile sostituire l'impostazione MEDIA_ROOT per i test utilizzando il @override_settings() decoratore as documented:

from django.test import override_settings 


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