私の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)
ビューを単体テストしたいと思います。幸せなパスと失敗したパスをテストする予定です。つまり、request.FILES
にはキー 'file'がありません。request.FILES['file']
にはNone
。があります。
ハッピーパスの投稿データを設定するにはどうすればよいですか?
From Django docs on Client.post
:
ファイルの送信は特別なケースです。ファイルに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 。をご覧になることをお勧めします。これは、リクエストで提供されるデータをモックする最良の方法です。
そうは言っても、私はあなたのコードにいくつかの欠陥を見つけました。
したがって、refactorのようなビューを使用して、次のような関数を使用することをお勧めします。
def upload_file_to_location(request, location=None): # Can use the default configured
そして、そのことをあざけります。 Python Mock を使用できます。
PS:Django Test Client を使用することもできますが、それは、クライアントがセッション、ミドルウェア、など。単体テストに似たものはありません。
私は自分のイベント関連のアプリケーションのためにこのようなことをしますが、あなたはあなた自身のユースケースに取り組むために十分以上のコードを持っている必要があります
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)
私はそのようなことをしました:
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。
Django 1.7では、TestCaseに問題がありますが、open(filepath、 'rb')を使用して解決できますが、テストクライアントを使用する場合、それを制御することはできません。 file.read()が常にバイトを返すようにします。
ソース: https://code.djangoproject.com/ticket/23912 、KevinEtienne
Rbオプションがないと、TypeErrorが発生します:
TypeError: sequence item 4: expected bytes, bytearray, or an object with the buffer interface, str found
from rest_framework.test import force_authenticate
from rest_framework.test import APIRequestFactory
factory = APIRequestFactory()
user = User.objects.get(username='#####')
view = <your_view_name>.as_view()
with open('<file_name>.pdf', 'rb') as fp:
request=factory.post('<url_path>',{'file_name':fp})
force_authenticate(request, user)
response = view(request)