122

私の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「ファイル」がない場合、request.FILES['file']ある場合None

ハッピー パスの投稿データを設定するにはどうすればよいですか?誰か教えてもらえますか?

4

14 に答える 14

139

以前は同じことをしていました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、 の代わりに objectを使用する必要がありますstr"file_content"に変更b"file_content"

それは正常に機能しており、通常のアップロードのように動作SimpleUploadedFileする を作成しInMemoryFile、名前、コンテンツ、およびコンテンツ タイプを選択できます。

于 2014-12-07T17:07:38.873 に答える
133

Django ドキュメントからClient.post:

ファイルの送信は特殊なケースです。ファイルを POST するには、ファイル フィールド名をキーとして指定し、アップロードするファイルのファイル ハンドルを値として指定するだけです。例えば:

c = Client()
with open('wishlist.doc') as fp:
  c.post('/customers/wishes/', {'name': 'fred', 'attachment': fp})
于 2012-06-23T14:55:00.680 に答える
7

Django RequestFactoryをご覧になることをお勧めします。リクエストで提供されたデータをモックする最良の方法です。

そうは言っても、あなたのコードにいくつかの欠陥が見つかりました。

  • 「ユニット」テストとは、機能の「ユニット」を1 つだけテストすることを意味します。したがって、そのビューをテストする場合は、実際には単体テストではなく、ビューとファイル システムをテストすることになります。この点をより明確にするために。そのテストを実行すると、ビューは正常に動作しますが、そのファイルを保存する権限がない場合、そのためにテストは失敗します。
  • 他に重要なのはテスト速度です。TDD のようなものを実行している場合、テストの実行速度は非常に重要です。 I/O にアクセスすることはお勧めできません

したがって、次のような関数を使用するようにビューをリファクタリングすることをお勧めします。

def upload_file_to_location(request, location=None): # Can use the default configured

そして、それを嘲笑してください。Python Mockを使用できます。

PS: Django Test Clientを使用することもできますが、それは、クライアントがセッション、ミドルウェアなどを利用するため、テストするために別のものを追加することを意味します。単体テストに似たものはありません。

于 2012-06-23T15:00:27.277 に答える
5

私は自分のイベント関連のアプリケーションでこのようなことをしていますが、自分のユースケースに取り組むには十分な数のコードが必要です

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)
于 2012-06-23T16:50:28.453 に答える
1

Django 1.7 では、Open(filepath, 'rb') を使用して解決できる TestCase に問題がありますが、テスト クライアントを使用する場合、それを制御することはできません。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
于 2015-03-10T22:58:29.827 に答える
1
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)
于 2019-07-11T10:30:34.833 に答える