как загрузить модульный тестовый файл в django
в моем приложении django у меня есть представление, которое выполняет загрузку файлов.Основной фрагмент кода выглядит так
...
if (request.method == 'POST'):
if request.FILES.has_key('file'):
file = request.FILES['file']
with open(settings.destfolder+'/%s' % file.name, 'wb+') as dest:
for chunk in file.chunks():
dest.write(chunk)
Я хотел бы юнит-тест вида.Я планирую проверить счастливый путь, а также неудачу path..ie, тот случай, когда request.FILES
не имеет ключа 'file', гдеrequest.FILES['file']
и None
..
как настроить данные post для счастливого пути?Может кто-нибудь мне сказать?
6 ответов:
из Django docs на
Client.post
:отправка файлов-это особый случай. Чтобы разместить файл, вам нужно только Укажите имя поля файла в качестве ключа и дескриптор файла для файла вы хотите загрузить в качестве значения. Например:
c = Client() with open('wishlist.doc') as fp: c.post('/customers/wishes/', {'name': 'fred', 'attachment': fp})
я делал то же самое
with open('some_file.txt') as fp:
но тогда мне нужны были изображения, видео и другие реальные файлы в РЕПО, а также я тестировал часть компонента ядра Django, который хорошо протестирован, поэтому в настоящее время это то, что я делаю:from django.core.files.uploadedfile import SimpleUploadedFile def test_upload_video(self): video = SimpleUploadedFile("file.mp4", "file_content", content_type="video/mp4") self.client.post(reverse('app:some_view'), {'video': video}) # some important assertions ...
на Python 3.5+ вы должны использовать
bytes
объект вместоstr
. Изменить"file_content"
доb"file_content"
он работает нормально,
SimpleUploadedFile
создаетInMemoryFile
это ведет себя как обычная загрузка, и вы можете выбрать наименование, содержание и тип контента.
Я рекомендую вам взглянуть на Django RequestFactory. Это лучший способ издеваться над данными, предоставленными в запросе.
сказал, что я нашел несколько недостатков в коде.
- "единичное" тестирование означает тестирование только один "блок" функциональность. Так, если вы хотите проверить это представление, вы будете тестировать представление и файл система, следовательно, не совсем модульный тест. Чтобы сделать этот момент более четко. Если вы запустите этот тест и работает отлично, но у тебя нет разрешения на сохранение этого файла, ваш тест не удастся из-за этого.
- другая важная вещь-это
Я делаю что-то вроде этого для моего собственного приложения, связанного с событиями, но у вас должно быть более чем достаточно кода, чтобы справиться с вашим собственным прецедентом
import tempfile, csv, os class UploadPaperTest(TestCase): def generate_file(self): try: myfile = open('test.csv', 'wb') wr = csv.writer(myfile) wr.writerow(('Paper ID','Paper Title', 'Authors')) wr.writerow(('1','Title1', 'Author1')) wr.writerow(('2','Title2', 'Author2')) wr.writerow(('3','Title3', 'Author3')) finally: myfile.close() return myfile def setUp(self): self.user = create_fuser() self.profile = ProfileFactory(user=self.user) self.event = EventFactory() self.client = Client() self.module = ModuleFactory() self.event_module = EventModule.objects.get_or_create(event=self.event, module=self.module)[0] add_to_admin(self.event, self.user) def test_paper_upload(self): response = self.client.login(username=self.user.email, password='foz') self.assertTrue(response) myfile = self.generate_file() file_path = myfile.name f = open(file_path, "r") url = reverse('registration_upload_papers', args=[self.event.slug]) # post wrong data type post_data = {'uploaded_file': i} response = self.client.post(url, post_data) self.assertContains(response, 'File type is not supported.') post_data['uploaded_file'] = f response = self.client.post(url, post_data) import_file = SubmissionImportFile.objects.all()[0] self.assertEqual(SubmissionImportFile.objects.all().count(), 1) #self.assertEqual(import_file.uploaded_file.name, 'files/registration/{0}'.format(file_path)) os.remove(myfile.name) file_path = import_file.uploaded_file.path os.remove(file_path)
в Django 1.7 есть проблема с TestCase, которая может быть решена с помощью open(filepath, 'rb'), но при использовании тестового клиента мы не контролируем его. Я думаю, что, вероятно, лучше всего обеспечить файл.read() возвращает всегда байт.
источник:https://code.djangoproject.com/ticket/23912, by KevinEtienne
без опции rb, TypeError поднимается:
TypeError: sequence item 4: expected bytes, bytearray, or an object with the buffer interface, str found
Я сделал что-то вроде этого :
from django.core.files.uploadedfile import SimpleUploadedFile from django.test import TestCase from django.core.urlresolvers import reverse from django.core.files import File from django.utils.six import BytesIO from .forms import UploadImageForm from PIL import Image from io import StringIO def create_image(storage, filename, size=(100, 100), image_mode='RGB', image_format='PNG'): """ Generate a test image, returning the filename that it was saved as. If ``storage`` is ``None``, the BytesIO containing the image data will be passed instead. """ data = BytesIO() Image.new(image_mode, size).save(data, image_format) data.seek(0) if not storage: return data image_file = ContentFile(data.read()) return storage.save(filename, image_file) class UploadImageTests(TestCase): def setUp(self): super(UploadImageTests, self).setUp() def test_valid_form(self): ''' valid post data should redirect The expected behavior is to show the image ''' url = reverse('image') avatar = create_image(None, 'avatar.png') avatar_file = SimpleUploadedFile('front.png', avatar.getvalue()) data = {'image': avatar_file} response = self.client.post(url, data, follow=True) image_src = response.context.get('image_src') self.assertEquals(response.status_code, 200) self.assertTrue(image_src) self.assertTemplateUsed('content_upload/result_image.html')
функция create_image создаст изображение, поэтому вам не нужно давать статический путь изображения.
Примечание : Вы можете обновить код как в код. Этот код для Python 3.6.