कैसे django में इकाई परीक्षण फ़ाइल अपलोड करने के लिए


99

मेरे 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..

मैं खुश रास्ते के लिए पोस्ट डेटा कैसे सेट कर सकता हूं? क्या कोई मुझे बता सकता है?


जैसा कि आपने क्लाइंट वर्ग का उपयोग करके उत्तर को सही के रूप में चिह्नित किया है, आप शायद एक यूनिट टेस्ट की तलाश में नहीं हैं, लेकिन एक कार्यात्मक परीक्षण ...
हेनिंग

जवाबों:


109

Django डॉक्स से Client.post:

फाइलें जमा करना एक विशेष मामला है। किसी फ़ाइल को पोस्ट करने के लिए, आपको केवल फ़ाइल फ़ील्ड नाम को एक कुंजी के रूप में प्रदान करना होगा, और उस फ़ाइल को एक फ़ाइल संभालना चाहिए जिसे आप मूल्य के रूप में अपलोड करना चाहते हैं। उदाहरण के लिए:

c = Client()
with open('wishlist.doc') as fp:
  c.post('/customers/wishes/', {'name': 'fred', 'attachment': fp})

12
प्रासंगिक Django डॉक्टर के लिए लिंक: docs.djangoproject.com/en/dev/topics/testing/overview/…
lsh


2
हेनिंग तकनीकी रूप से सही है - यह एक अधिक होगा integration test- वास्तव में तब तक कोई फर्क नहीं पड़ता जब तक कि आप अधिक जटिल कोड बेस में नहीं आते हैं, शायद एक वास्तविक परीक्षण टीम के साथ भी
एल्विन

एक वेब फ्रेमवर्क में, यदि आप विचारों का परीक्षण कर रहे हैं तो यह बहुत कम अंतर रखता है। फ़ंक्शन के माध्यम से क्लाइंट बनाम सीधे प्रतिक्रिया प्राप्त करना, अधिकांश परीक्षणों के मान्य होने के लिए समान है। साथ ही क्लाइंट आपको अधिक लचीलापन देता है। यही मैं उपयोग करता हूं, व्यक्तिगत रूप से।
trpt4him

प्रासंगिक Django डॉक के लिए अद्यतन लिंक: docs.djangoproject.com/en/dev/topics/testing/tools/…
फ्रीज किया

109

मैं ऐसा ही करता था, 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 ...

में अजगर 3.5+ आप उपयोग करने की आवश्यकता bytesके बजाय वस्तु str। बदलें "file_content"करने के लिएb"file_content"

यह ठीक काम कर रहा गया है, SimpleUploadedFileएक बनाता है InMemoryFileकि एक नियमित अपलोड की तरह बर्ताव करता है और आप नाम, सामग्री और सामग्री प्रकार चुन सकते हैं।


1
आपके उदाहरण का उपयोग करते हुए, प्रपत्र सत्यापन मुझे देता है: "एक वैध छवि अपलोड करें। आपके द्वारा अपलोड की गई फ़ाइल या तो छवि या दूषित छवि नहीं थी।"
Antonagestam

@antonagestam क्या आप सही सामग्री प्रकार पास कर रहे हैं? क्या आपका फ़ॉर्म फ़ाइल की सामग्री को मान्य कर रहा है? यदि ऐसा है तो "file_content"एक वैध छवि हेडर होना चाहिए ताकि आपका कोड सोचें कि यह एक वैध छवि है।
डेनिलो कैबेलो

जेपीईजी और पीएनजी के लिए उपयुक्त हेडर क्या हैं?
अनुनागस्तम

2
इस समस्या के लिए इसे सही उत्तर माना जाना चाहिए। धन्यवाद @DaniloCabello
19

1
आप base64.b64d timecode ("iVBORw0KGgoAAAANSUhEUgAAAAUA" + "AAAFCAYAAACNbyblAAAAHElEQVQI12P4/" - 8/ w38GIAXDIBKE0DHxgljNBAAO "+" 9TXL "का उपयोग कर सकते हैं।" 9TXL "
होवेदो

6

मैं आपको Django RequestFactory पर एक नज़र डालने की सलाह देता हूं । यह अनुरोध में दिए गए डेटा का मजाक उड़ाने का सबसे अच्छा तरीका है।

कहा कि, मुझे आपके कोड में कई खामियां मिलीं।

  • "यूनिट" परीक्षण का मतलब कार्यक्षमता की सिर्फ एक "यूनिट" का परीक्षण करना है। इसलिए, यदि आप उस दृश्य का परीक्षण करना चाहते हैं जिसे आप दृश्य परीक्षण कर रहे हैं, और फ़ाइल सिस्टम, एर्गो, वास्तव में यूनिट परीक्षण नहीं है। इस बात को और स्पष्ट करने के लिए। यदि आप उस परीक्षण को चलाते हैं, और दृश्य ठीक काम करता है, लेकिन आपके पास उस फ़ाइल को सहेजने की अनुमति नहीं है, तो उसका परीक्षण विफल हो जाएगा।
  • अन्य महत्वपूर्ण बात परीक्षण की गति है । यदि आप TDD जैसा कुछ कर रहे हैं तो आपके परीक्षणों के निष्पादन की गति वास्तव में महत्वपूर्ण है। किसी भी I / O तक पहुँचना अच्छा विचार नहीं है

इसलिए, मैं आपको सलाह देता हूं कि आप किसी फ़ंक्शन का उपयोग करने के लिए अपना दृष्टिकोण फिर से निर्धारित करें:

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

और उस पर कुछ मज़ाक करते हैं। आप पायथन मॉक का उपयोग कर सकते हैं ।

पुनश्च: आप Django टेस्ट क्लाइंट का उपयोग भी कर सकते हैं लेकिन इसका मतलब यह होगा कि आप परीक्षण करने के लिए एक और चीज़ जोड़ रहे हैं, क्योंकि वह ग्राहक सत्र, मिडलवेज़, आदि का उपयोग यूनिट परीक्षण के समान नहीं है।


1
मैं गलत हो सकता हूं, लेकिन ऐसा लगता है कि वह परीक्षण का एकीकरण करने के लिए है और सिर्फ 'यूनिट टेस्ट' शब्द का गलत इस्तेमाल किया है।
13

1
@santiagobasulto मैं TDD में नौसिखिया हूं और मैं अपनी इकाई परीक्षण को गति देना चाहता हूं। लेकिन मेरे पास फ़ाइल अपलोड से संबंधित कई विचार हैं जो यूनिट परीक्षण के दौरान रिमोट स्टोरेज (अमेज़ॅन एस 3) पर फ़ाइलों को अपलोड करते हैं। एक ऐसा समय लगता है। क्या आप विवरण में दिखाने के लिए अपने उत्तर का विस्तार कर सकते हैं कि परीक्षण करते समय I / O तक पहुंचने से कैसे बचें?
दिमित्री वोज्शिकोस्की

5
हे @ दमित्री। मॉक वहां जाने का रास्ता है। जब भी आपको किसी बाहरी संसाधन का उपयोग करना होता है तो आपको उसका मजाक उड़ाना चाहिए। मान लीजिए कि आपके पास एक दृश्य है जिसे profile_pictureआंतरिक रूप से एक upload_profile_pictureफ़ंक्शन का उपयोग करने के लिए कहा जाता है । यदि आप उस दृश्य का परीक्षण करना चाहते हैं, तो केवल आंतरिक फ़ंक्शन का मज़ाक उड़ाएँ और सुनिश्चित करें कि यह आपके परीक्षण पर कहा गया है। यह एक सरल उदाहरण है: gist.github.com/santiagobasulto/6437356
santiagobasulto

4

मैं अपने स्वयं के ईवेंट संबंधित एप्लिकेशन के लिए कुछ ऐसा करता हूं, लेकिन आपके पास अपने उपयोग के मामले के लिए पर्याप्त कोड होना चाहिए

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)

4

मैंने ऐसा कुछ किया:

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 फ़ंक्शन छवि बनाएगा ताकि आपको छवि का स्थिर मार्ग देने की आवश्यकता न हो।

नोट: आप कोड के अनुसार कोड अपडेट कर सकते हैं। पायथन 3.6 के लिए यह कोड।


1

Django 1.7 में TestCase विच के साथ एक समस्या है जिसे ओपन (फाइलपैथ, 'आरबी') का उपयोग करके हल किया जा सकता है लेकिन टेस्ट क्लाइंट का उपयोग करते समय हमारा इस पर कोई नियंत्रण नहीं है। मुझे लगता है कि file.read () रिटर्न हमेशा बाइट सुनिश्चित करना सबसे अच्छा है।

स्रोत: केविनएटन द्वारा https://code.djangoproject.com/ticket/23912

Rb विकल्प के बिना, एक TypeError उठाया जाता है:

TypeError: sequence item 4: expected bytes, bytearray, or an object with the buffer interface, str found

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)

APIRequestFactory
majkelx

0

जैसा कि Django के आधिकारिक दस्तावेज में उल्लिखित है :

फाइलें जमा करना एक विशेष मामला है। किसी फ़ाइल को पोस्ट करने के लिए, आपको केवल फ़ाइल फ़ील्ड नाम को एक कुंजी के रूप में प्रदान करना होगा, और उस फ़ाइल को एक फ़ाइल संभालना चाहिए जिसे आप मूल्य के रूप में अपलोड करना चाहते हैं। उदाहरण के लिए:

c = Client()
with open('wishlist.doc') as fp:
    c.post('/customers/wishes/', {'name': 'fred', 'attachment': fp})

अधिक जानकारी: फ़ाइल को किसी फ़ंक्शन के तर्क के रूप में पारित किया गया है, तो कैसे जांचें?

परीक्षण करते समय, कभी-कभी हम यह सुनिश्चित करना चाहते हैं कि फ़ाइल किसी फ़ंक्शन के तर्क के रूप में पारित हो।

जैसे

...
class AnyView(CreateView):
    ...
    def post(self, request, *args, **kwargs):
        attachment = request.FILES['attachment']
        # pass the file as an argument
        my_function(attachment)
        ...

परीक्षणों में, पायथन के नकली का उपयोग कुछ इस तरह से करें:

# Mock 'my_function' and then check the following:

response = do_a_post_request()

self.assertEqual(mock_my_function.call_count, 1)
self.assertEqual(
    mock_my_function.call_args,
    call(response.wsgi_request.FILES['attachment']),
)

0
from django.test import Client
from requests import Response

client = Client()
with open(template_path, 'rb') as f:
    file = SimpleUploadedFile('Name of the django file', f.read())
    response: Response = client.post(url, format='multipart', data={'file': file})

उम्मीद है की यह मदद करेगा।


0

मैं पायथन == 3.8.2, Django == 3.0.4, djangorestframework == 3.11.0 का उपयोग कर रहा हूं

मैंने कोशिश की, self.client.postलेकिन एक Resolver404अपवाद मिला ।

मेरे लिए काम करने के बाद:

import requests
upload_url='www.some.com/oaisjdoasjd' # your url to upload
with open('/home/xyz/video1.webm', 'rb') as video_file:
    # if it was a text file we would perhaps do
    # file = video_file.read()
    response_upload = requests.put(
        upload_url,
        data=video_file,
        headers={'content-type': 'video/webm'}
    )
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.