2010-11-26 10 views
33

Ich habe ein Modell mit einem FileField. Ich möchte es zusammenfügen. Django-Test-Framework bietet großartige Möglichkeiten, um Datenbanken und E-Mails zu verwalten. Gibt es etwas Ähnliches für FileFields?Was ist die saubere Art, FileField in django zu testen?

Wie kann ich sicherstellen, dass die Komponententests nicht die reale Anwendung verschmutzen?

Vielen Dank im Voraus

PS: Meine Frage ist fast ein Duplikat Django test FileField using test fixtures aber es hat nicht eine akzeptierte Antwort. Ich möchte nur noch einmal nachfragen, ob es etwas Neues zu diesem Thema gibt.

+1

Mögliche Duplikate von [Django Test FileField mit Test Fixtures] (http://StackOverflow.com/Questions/2266503/django-test-filefield-using-test-fixtures) – waterproof

Antwort

31

Es gibt mehrere Möglichkeiten, wie Sie damit umgehen können, aber sie sind alle hässlich, da Komponententests isoliert werden sollen, aber Dateien sind alles über dauerhafte Änderungen.

Meine Komponententests werden nicht auf einem System mit Produktionsdaten ausgeführt, daher war es einfach, das Upload-Verzeichnis nach jedem Lauf einfach wieder auf git reset --hard zurückzusetzen. Dieser Ansatz ist in gewisser Weise der beste Weg, da er keine Codeänderungen erfordert und garantiert funktioniert, solange Sie mit guten Testdaten beginnen.

Wenn Sie tatsächlich brauchen nicht mit dieser Datei nichts tun nach Methode speichert Ihr Modell zu testen, würde ich empfehlen, Michael Foord ausgezeichnete Mock library mit auf die File Instanz (dh so etwas wie mock_file = Mock(spec=django.core.files.File); mock_file.read.return_value = "fake file contents") komplett gefälscht, so dass Sie vollständig vermeiden Änderungen an Ihrer Dateiverarbeitungslogik Die Mock-Bibliothek hat ein paar Möglichkeiten, globally patch Django File class innerhalb einer Testmethode, die etwa so einfach ist, wie dies wird.

Wenn Sie eine echte Datei benötigen (zB um einen Test zu testen, mit einem externen Skript zu bearbeiten usw.) können Sie etwas Ähnliches wie Mirkos Beispiel verwenden und ein File object erstellen, nachdem Sie sich vergewissert haben irgendwo angemessen gespeichert - hier sind drei Möglichkeiten, dies zu tun:

  • Haben Sie Ihren Test settings.MEDIA_ROOT Punkt in ein temporäres Verzeichnis (siehe die Python tempfile Moduls mkdtemp-Funktion). Dies funktioniert, solange Sie eine separate STATIC_ROOT haben, die Sie für die Mediendateien verwenden, die Teil Ihres Quellcodes sind.
  • Verwenden Sie ein benutzerdefinierten storage manager
  • den Dateipfad manuell auf jede Datei Instanz Set oder eine benutzerdefinierten upload_to Funktion haben irgendwo die Ihre Test-Setup/Teardown Prozess Säuberungen wie ein Testunterverzeichnis unter MEDIA_ROOT zu zeigen.
+0

Danke für diese großartige Antwort. Ich wähle schließlich einen unit-Test MEDIA_ROOT, indem ich den Wert dieser Variable im setUp meines Testfalls ändere – luc

+1

mock ist jetzt Teil der Python-Standardbibliothek, verfügbar als unattest.mock in Python 3.3 weiter - gesammelt von REAME. rst – chachan

+0

@chachan können Sie eine Bearbeitung vorschlagen? Diese Antwort ist definitiv fällig für ein Update –

10

ich normalerweise testen filefields in Modellen doctest

>>> from django.core.files import File 
>>> s = SimpleModel() 
>>> s.audio_file = File(open("media/testfiles/testaudio.wav")) 
>>> s.save() 
>>> ... 
>>> s.delete() 

mit der Wenn ich mit Test-Clients ich auch Testdatei Uploads müssen.

Wie bei Fixtures, kopiere ich einfach die Dateien, die ich brauche, in einen Testordner, nachdem ich die Pfade im Fixture geändert habe.

z.B.

In einer Fixture, die Modelle mit Dateifeilen enthält, die auf ein Verzeichnis namens "audio" verweisen, ersetzen Sie "audio": "audio/audio.wav" durch "audio": "audio/test/audio.wav".
Nun müssen Sie nur noch den Testordner mit den notwendigen Dateien in "audio" im Test-Setup kopieren und dann in tearDown löschen.

Nicht die sauberste Art, die ich je denke, aber das ist was ich tue.

+0

Wie kann ich das mit einem ImageField ?? ? –

+0

Muss ich das Dateihandle manuell schließen, um die von ihm verwendeten Ressourcen freizugeben? – Pieter

0

Wenn Sie wollen einfach nur ein Objekt erstellen, die Filefield und erfordert nicht wollen, um dieses Feld verwenden dann können Sie passieren einfach jede (bestehende oder nicht) relativen Pfad wie folgt aus:

self.example_object = models.ExampleModel({'file': "foo.bar"}) 
self.example_object.save() 

Dann ist es betriebsbereit.

58

Django bietet eine gute Möglichkeit, dies zu tun - verwenden Sie eine SimpleUploadedFile.

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.

+0

Ich wusste das nicht. Vielen Dank für Ihren Kommentar. Ich werde es untersuchen – luc

+5

Der Inhalt * muss * sein str() in Python 2.x und Bytes() in Python 3.x. Du kannst dort keinen Text/Unicode einfügen. – kaleissin

+1

Ich weiß, ich frage das 4 Jahre später, aber ... Gibt es eine Möglichkeit, die Dateigröße zu fälschen? – pta2002

Verwandte Themen