2010-02-15 27 views
22

Ich versuche Tests für einige Modelle zu erstellen, die ein FileField haben. Das Modell sieht wie folgt aus:Django Test FileField mit Test Fixtures

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

ich zwei Probleme haben:

  1. Wenn an einer Halterung zum Speichern von Daten ./manage.py dumpdata verwenden, werden die Dateiinhalte nicht gespeichert, wird nur der Dateiname wird in die gespeicherte Leuchte. Während ich finde, dass dies das erwartete Verhalten ist, da die Dateiinhalte nicht in der Datenbank gespeichert werden, möchte ich diese Informationen irgendwie in das Gerät für Tests einbeziehen.

  2. Ich habe einen Testfall für Hochladen einer Datei, die wie folgt aussieht:

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

Während dieser Test funktioniert gut, es lässt die hochgeladene Datei im Medienverzeichnis nach Fertigstellung. Natürlich konnte die Löschung in tearDown() erledigt werden, aber ich fragte mich, ob Django einen anderen Weg hatte, damit umzugehen.

Eine Lösung, an die ich dachte, war die Verwendung eines anderen Medienordners für Tests, die mit den Testvorrichtungen synchronisiert werden müssen. Gibt es eine Möglichkeit, ein anderes Medienverzeichnis in anzugeben, wenn Tests ausgeführt werden? Und kann ich eine Art Hook zu dumpdata hinzufügen, damit die Dateien in den Medienordnern synchronisiert werden?

Gibt es also eine mehr Pythonic oder Django-spezifische Art des Umgangs mit Komponententests mit Dateien?

+0

So os.remove (foo) does't Arbeit? Wird eine Ausnahme ausgelöst? Vielleicht gibt es nicht die richtigen privs auf diesem Verzeichnis/Datei, um es aus Ihrem Komponententest löschen zu können? –

+0

Das 'os.remove() 'Teil im Code löscht die Datei aus dem temporären Verzeichnis. Um die hochgeladene Datei zu löschen, müsste ich in das Medienverzeichnis schauen und einer komplizierteren Logik folgen, um den genauen Speicherort der Datei zu finden. Ich suche nach einem einfacheren, automatisierten Weg, es zu tun, wenn es überhaupt existiert. – sttwister

+1

D'oh, Entschuldigung! Ich habe deinen Beitrag falsch gelesen. Wie wäre es mit hacking settings.MEDIA_ROOT = '/ pfad/zu/project/statisch/und/dann/alternative/speicher /' und einstellungen.MEDIA_URL = '/ statisch/und/dann/alternative/speicher /' in ihrem setup für ihre tests ? Hacky, aber könnte den Job machen ... –

Antwort

17

Django bietet eine gute Möglichkeit, Tests auf FileFields zu schreiben, ohne sich um in der realen Dateisystem Ausmisten - ein SimpleUploadedFile verwenden.

from django.core.files.uploadedfile import SimpleUploadedFile 

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

Es ist eines der django magischen Eigenschaften-dieser-nicht-show-up-in-the-docs :). Es wird jedoch auf here verwiesen.

+3

Nicht-binäre Inhalte verursachen einen Fehler in Python 3+; Sie können das beheben, indem Sie einfach den Inhalt wie folgt in Binärform bringen: 'my_model.file_field = SimpleUploadedFile ('best_file_eva.txt', b'das sind die Dateiinhalte! ')' – LaundroMat

3

Ich habe Einheitentests für eine ganze Galerie-App geschrieben, und was für mich gut funktionierte, war die Verwendung der Python-Module tempfile und shutil, um Kopien der Testdateien in temporären Verzeichnissen zu erstellen und anschließend alle zu löschen.

Das folgende Beispiel funktioniert nicht/vollständig, aber sollten Sie auf dem richtigen Weg:

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) 

ich diese Methoden in der setUp run() und tearDown() Methoden meiner Unit-Tests und es funktioniert groß! Sie haben eine saubere Kopie Ihrer Dateien, um Ihr Dateifeld zu testen, das wiederverwendbar und vorhersehbar ist.

+0

Ich sehe nicht, wie das mir helfen kann. Ich möchte Djangos Medienverzeichnis mit einem Test überschreiben. Und ich möchte auch irgendwie die Dateien exportieren/kopieren, wenn './manage.py dumpdata' verwendet wird. – sttwister

+0

Das Überschreiben von Djangos Medienverzeichnis ist eine schlechte Idee. Wenn Sie das aktuelle Medienverzeichnis nicht an einen anderen Ort verschieben und später wieder einfügen, können Sie nie Tests auf Ihrer Live-Site durchführen, da dies eine destruktive Maßnahme wäre. Du * kannst * den Medienordner verschieben und ihn wie oben erwähnt mit den Shutles zurücklegen. Darüber hinaus wird dumpdata niemals Dateien für Sie exportieren. Sie müssen dafür Ihr eigenes Skript oder die manage.py-Erweiterung schreiben. –

0

Dies ist, was ich für meinen Test gemacht habe. Nach dem Hochladen der Datei sollte es nach oben in der Foto Eigenschaft meiner Organisation Modellobjekt Ende:

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

können Sie überschreiben die MEDIA_ROOT Einstellung für Ihre Tests die @override_settings() Dekorateur as documented mit:

from django.test import override_settings 


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