Каков чистый способ юнит-тестирования FileField в Django? - PullRequest
45 голосов
/ 26 ноября 2010

У меня есть модель с FileField. Я хочу протестировать это. Тестовый фреймворк django предлагает отличные способы управления базой данных и электронной почтой. Есть ли что-то похожее для FileFields?

Как я могу убедиться, что юнит-тесты не будут загрязнять реальное приложение?

Заранее спасибо

PS: Мой вопрос почти дубликат теста Django FileField с использованием тестовых приборов , но он не имеет принятого ответа Просто хочу еще раз спросить, если что-то новое в этой теме.

Ответы [ 4 ]

81 голосов
/ 11 декабря 2013

Django предоставляет отличный способ сделать это - использовать SimpleUploadedFile.

from django.core.files.uploadedfile import SimpleUploadedFile

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

Это одна из волшебных функций django, которые не показываются в документах :).Однако здесь упоминается .

36 голосов
/ 28 декабря 2010

Есть несколько способов справиться с этим, но все они безобразны, поскольку модульные тесты должны быть изолированными, а файлы - это долговременные изменения.

Мои модульные тесты не запускаются в системе спроизводственные данные, поэтому было легко просто сбросить каталог загрузки после каждого запуска, например git reset --hard.Этот подход является в некотором смысле лучшим просто потому, что он не требует изменений кода и гарантированно будет работать, если вы начнете с хороших тестовых данных.

Если вам на самом деле ничего не нужно делать с этим файлом после тестирования метода сохранения вашей модели, я бы рекомендовал использовать превосходную библиотеку Python Mock , чтобы полностью подделать экземпляр File (то есть что-то вроде mock_file = Mock(spec=django.core.files.File); mock_file.read.return_value = "fake file contents"), так что вы можете полностью избежать изменений в логике обработки файлов.В библиотеке Mock есть несколько способов глобальное исправление класса файлов Django в методе тестирования, который настолько прост, насколько это возможно.

Если вам нужноиметь настоящий файл (т. е. для использования в качестве части теста, обработки с помощью внешнего скрипта и т. д.), вы можете использовать что-то похожее на пример Мирко и создать объект File , убедившись, что он будет сохраненгде-то уместно - вот три способа сделать это:

  • Пусть ваш тест settings.MEDIA_ROOT указывает на временный каталог (см. функцию mkdtemp модуля Python tempfile ).Это прекрасно работает, если у вас есть что-то вроде отдельного STATIC_ROOT, который вы используете для медиа-файлов, являющихся частью вашего исходного кода.
  • Используйте пользовательский менеджер хранилища
  • Задайте путь к файлу вручную для каждого экземпляра файла или используйте пользовательскую функцию upload_to , чтобы указать куда-то, что очищает процесс установки / демонтажа теста, например, подкаталог test в MEDIA_ROOT.
12 голосов
/ 26 ноября 2010

Я обычно тестирую файловые поля в моделях, использующих doctest

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

Если мне нужно, я также проверяю загрузку файлов с помощью тестовых клиентов.

Что касается приборов, я просто копирую нужные мне файлы в тестовую папку после изменения путей в приспособлении.

, например

В приборе, содержащем модели с файловыми файлами, указывающими на каталог с именем «audio», вы заменяете «audio»: «audio / audio.wav» на «audio»: «audio / test / audio.wav».
Теперь все, что вам нужно сделать, это скопировать тестовую папку с необходимыми файлами в «audio» в наборе тестов и затем удалить ее в tearDown.

Не самый чистый способ, который я когда-либо думал, но это то, что я делаю.

0 голосов
/ 16 марта 2012

Если вы просто хотите создать объект , для которого требуется FileField и не хотите использовать это поле , тогда вы можете просто пропустить любой (существующий или нет) относительный путь, подобный этому :

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

Тогда он готов к использованию.

...