Каков чистый способ unittest FileField в django?
У меня есть модель с FileField. Я хочу это сделать. В платформе django test есть отличные способы управления базами данных и электронной почтой. Есть ли что-то подобное для FileFields?
Как я могу убедиться, что unittests не загрязнят реальное приложение?
Заранее спасибо
PS: Мой вопрос - почти дубликат Django testFieldField с использованием тестовых устройств, но у него нет принятого ответа. Просто хочу спросить, есть ли что-то новое в этой теме.
Ответы
Ответ 1
Есть несколько способов справиться с этим, но все они безобразны, так как модульные тесты должны быть изолированными, а файлы - о долговременных изменениях.
Мои модульные тесты не выполняются в системе с производственными данными, поэтому было легко просто сбросить каталог загрузки после каждого запуска с чем-то вроде git reset --hard
. Этот подход является в некотором смысле лучшим просто потому, что он не требует изменений кода и гарантированно будет работать, если вы начнете с хороших тестовых данных.
Если вам на самом деле ничего не нужно делать с этим файлом после тестирования метода сохранения модели, я бы порекомендовал использовать превосходную Mock-библиотеку pya, чтобы полностью подделать экземпляр File
(то есть что-то вроде mock_file = Mock(spec=django.core.files.File); mock_file.read.return_value = "fake file contents"
), чтобы вы могли полностью избежать изменений в логике обработки файлов. В библиотеке Mock есть несколько способов глобально исправить Django класс файлов в тестовом методе, который настолько прост, насколько это возможно.
Если вам нужен реальный файл (т.е. для использования в качестве части теста, обработки с помощью внешнего скрипта и т.д.), Вы можете использовать что-то похожее на пример Мирко и создать объект File, убедившись в этом. будет храниться в подходящем месте - вот три способа сделать это:
- Пусть ваш тест
settings.MEDIA_ROOT
указывает на временный каталог (см. функцию Python временного файла модуля mkdtemp
). Это прекрасно работает, если у вас есть что-то вроде отдельного STATIC_ROOT
, который вы используете для медиа файлов, которые являются частью вашего исходного кода.
- Используйте собственный диспетчер хранилища
- Задайте путь к файлу вручную для каждого экземпляра файла или используйте пользовательскую функцию upload_to, чтобы указать куда-то, что очищает процесс установки/удаления теста, например подкаталог test в
MEDIA_ROOT
.
Редактировать: библиотека фиктивных объектов появилась в Python версии 3.3. Для более старых версий Python проверьте версию Michael Foord
Ответ 2
Django предоставляет отличный способ сделать это - использовать SimpleUploadedFile.
from django.core.files.uploadedfile import SimpleUploadedFile
my_model.file_field = SimpleUploadedFile(
"best_file_eva.txt",
b"these are the file contents!" # note the b in front of the string [bytes]
)
Это одна из магических функций Django, которые не появляются в документах :). Однако он упоминается здесь как here.
Для Python 2
Если вы застряли на Python 2, пропустите префикс b
в содержимом:
my_model.file_field = SimpleUploadedFile(
"best_file_eva.txt",
"these are the file contents!" # no b
)
Ответ 3
Я обычно тестирую файловые поля в моделях с помощью 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" в тестовом комплектеUp и затем удалить ее в tearDown.
Не самый чистый путь, когда-либо я думаю, но это то, что я делаю.
Ответ 4
Если вы просто хотите создать объект, для которого требуется FileField, и не хотите использовать это поле, тогда вы можете просто передать любой (существующий или нет) относительный путь, например так:
example_object = models.ExampleModel({'file': "foo.bar"})
example_object.save()
Тогда он готов к использованию.