Django 2.1 - Writing your first Django app, part 5

अपना पहला Django ऐप लिखना, भाग 5




django

अपना पहला Django ऐप लिखना, भाग 5

यह ट्यूटोरियल शुरू होता है जहां ट्यूटोरियल 4 छोड़ा गया है। हमने एक वेब-पोल एप्लिकेशन बनाया है, और अब हम इसके लिए कुछ स्वचालित परीक्षण बनाएंगे।

पेश है स्वचालित परीक्षण

स्वचालित परीक्षण क्या हैं?

टेस्ट सरल दिनचर्या हैं जो आपके कोड के संचालन की जांच करते हैं।

परीक्षण विभिन्न स्तरों पर संचालित होता है। कुछ परीक्षण एक छोटे से विवरण पर लागू हो सकते हैं ( क्या एक विशेष मॉडल विधि मानों को उम्मीद के मुताबिक वापसी करती है? ) जबकि अन्य सॉफ्टवेयर के समग्र संचालन की जांच करते हैं ( साइट पर उपयोगकर्ता इनपुट का अनुक्रम वांछित परिणाम का उत्पादन करता है? )। यह आपके द्वारा पहले ट्यूटोरियल 2 में किए गए परीक्षण के तरीके से अलग नहीं है, shell का उपयोग किसी विधि के व्यवहार की जांच करने के लिए, या एप्लिकेशन को चलाकर और डेटा दर्ज करके यह जांचने के लिए कि यह कैसे व्यवहार करता है।

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

आपको परीक्षण बनाने की आवश्यकता क्यों है

तो परीक्षण क्यों बनाएं, और अब क्यों?

आप महसूस कर सकते हैं कि आपके पास अपनी प्लेट पर काफी पर्याप्त है बस पायथन / Django सीखने, और सीखने और करने के लिए अभी तक एक और चीज भारी और शायद अनावश्यक लगती है। आखिरकार, हमारे चुनाव आवेदन अब बहुत खुशी से काम कर रहे हैं; स्वचालित परीक्षण बनाने की परेशानी से गुजरना किसी भी बेहतर काम को करने वाला नहीं है। यदि पोल एप्लिकेशन का निर्माण करना Django प्रोग्रामिंग का अंतिम बिट है जिसे आप कभी भी करेंगे, तो सच है, आपको यह जानने की आवश्यकता नहीं है कि स्वचालित परीक्षण कैसे बनाएं। लेकिन, अगर ऐसा नहीं है, तो अब सीखने के लिए एक उत्कृष्ट समय है।

टेस्ट से आपका समय बचेगा

एक निश्चित बिंदु तक, 'यह देखना कि यह काम करने लगता है' एक संतोषजनक परीक्षा होगी। अधिक परिष्कृत अनुप्रयोग में, आपके पास घटकों के बीच दर्जनों जटिल इंटरैक्शन हो सकते हैं।

उन घटकों में से किसी में परिवर्तन से एप्लिकेशन के व्यवहार पर अप्रत्याशित परिणाम हो सकते हैं। यह जांचना कि यह अभी भी 'काम करने लगता है' का मतलब यह हो सकता है कि आपके परीक्षण डेटा के बीस विभिन्न रूपों के साथ आपके कोड की कार्यक्षमता के माध्यम से चल रहा है, यह सुनिश्चित करने के लिए कि आपने कुछ नहीं तोड़ा है - आपके समय का अच्छा उपयोग नहीं।

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

कभी-कभी यह अपने आप को अपने उत्पादक, रचनात्मक प्रोग्रामिंग कार्य से दूर करने के लिए एक झंझट का काम लग सकता है, विशेष रूप से लेखन परीक्षणों के अस्पष्ट और अस्पष्ट व्यवसाय का सामना करने के लिए, खासकर जब आप जानते हैं कि आपका कोड ठीक से काम कर रहा है।

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

टेस्ट केवल समस्याओं की पहचान नहीं करते, वे उन्हें रोकते हैं

यह केवल एक नकारात्मक पहलू के रूप में परीक्षणों के बारे में सोचने की गलती है।

परीक्षणों के बिना, एक आवेदन का उद्देश्य या इच्छित व्यवहार बल्कि अपारदर्शी हो सकता है। यहां तक ​​कि जब यह आपका अपना कोड होता है, तो आप कभी-कभी अपने आप को इसमें झांकते हुए पाएंगे कि यह पता लगाने की कोशिश कर रहा है कि यह वास्तव में क्या कर रहा है।

टेस्ट बदलते हैं कि; वे आपके कोड को अंदर से हल्का करते हैं, और जब कुछ गलत होता है, तो वे उस हिस्से पर प्रकाश केंद्रित करते हैं जो गलत हो गया है - भले ही आपको एहसास नहीं हुआ था कि यह गलत हो गया है

टेस्ट आपके कोड को अधिक आकर्षक बनाते हैं

आपने एक शानदार सॉफ्टवेयर बनाया होगा, लेकिन आप पाएंगे कि कई अन्य डेवलपर्स इसे देखने से इंकार कर देंगे क्योंकि इसमें परीक्षणों की कमी है; परीक्षण के बिना, वे इस पर भरोसा नहीं करेंगे। Django के मूल डेवलपर्स में से एक जैकब कापलान-मॉस कहते हैं, "कोड बिना परीक्षणों के डिजाइन द्वारा तोड़ा जाता है।"

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

टेस्ट टीम को एक साथ काम करने में मदद करते हैं

पिछले अंक एक आवेदन को बनाए रखने वाले एकल डेवलपर के दृष्टिकोण से लिखे गए हैं। टीमों द्वारा जटिल अनुप्रयोगों को बनाए रखा जाएगा। परीक्षण की गारंटी है कि सहकर्मी अनजाने में आपके कोड को नहीं तोड़ते हैं (और यह कि आप बिना जाने उन्हें नहीं तोड़ते हैं)। यदि आप एक Django प्रोग्रामर के रूप में एक जीवित करना चाहते हैं, तो आपको परीक्षण लिखने में अच्छा होना चाहिए!

बुनियादी परीक्षण रणनीतियों

लेखन परीक्षण के लिए कई तरीके हैं।

कुछ प्रोग्रामर " परीक्षण-संचालित विकास " नामक एक अनुशासन का पालन करते हैं; अपने कोड लिखने से पहले वे वास्तव में अपने परीक्षण लिखते हैं। यह काउंटर-सहज ज्ञान युक्त लग सकता है, लेकिन वास्तव में यह वैसे ही है जैसा कि ज्यादातर लोग अक्सर करते हैं: वे एक समस्या का वर्णन करते हैं, फिर इसे हल करने के लिए कुछ कोड बनाते हैं। टेस्ट संचालित विकास केवल पायथन टेस्ट मामले में समस्या को औपचारिक रूप देता है।

अधिक बार, परीक्षण के लिए एक नवागंतुक कुछ कोड बनाएगा और बाद में निर्णय करेगा कि इसके कुछ परीक्षण होने चाहिए। शायद पहले कुछ परीक्षण लिखना बेहतर होता, लेकिन इसे शुरू करने में कभी देर नहीं होती।

कभी-कभी यह पता लगाना मुश्किल होता है कि लेखन परीक्षण के साथ कहां से शुरुआत करें। यदि आपने पायथन की कई हजार पंक्तियाँ लिखी हैं, तो परीक्षण के लिए कुछ चुनना आसान नहीं होगा। ऐसी स्थिति में, जब आप कोई नई सुविधा जोड़ते हैं या बग को ठीक करते हैं, तो अगली बार अपना पहला परीक्षण लिखना फलदायक होता है।

तो चलो ठीक है।

हमारा पहला टेस्ट लिखना

हम एक बग की पहचान करते हैं

सौभाग्य से, polls आवेदन में थोड़ी सी गड़बड़ी हमें अभी ठीक करने के लिए है: Question.was_published_recently() pub_date Question.was_published_recently() विधि True यदि Question अंतिम दिन (जो सही है) के भीतर प्रकाशित किया गया था, लेकिन यह भी कि Question 's pub_date फ़ील्ड है भविष्य में (जो निश्चित रूप से नहीं है)।

एक प्रश्न पर विधि की जांच के लिए shell का उपयोग करके बग की पुष्टि करें, जिसकी तारीख भविष्य में है:

$ python manage.py shell
...\> py manage.py shell
>>> import datetime
>>> from django.utils import timezone
>>> from polls.models import Question
>>> # create a Question instance with pub_date 30 days in the future
>>> future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
>>> # was it published recently?
>>> future_question.was_published_recently()
True

चूंकि भविष्य में चीजें 'हाल' में नहीं हैं, इसलिए यह स्पष्ट रूप से गलत है।

बग को उजागर करने के लिए एक परीक्षण बनाएं

समस्या के लिए परीक्षण करने के लिए हमने जो कुछ किया है, वह वही है जो हम एक स्वचालित परीक्षण में कर सकते हैं, इसलिए चलो उसे एक स्वचालित परीक्षण में बदल दें।

एप्लिकेशन के परीक्षण के लिए एक पारंपरिक स्थान एप्लिकेशन के tests.py फ़ाइल में है; परीक्षण प्रणाली स्वचालित रूप से किसी भी फ़ाइल में परीक्षण पाएगी जिसका नाम test शुरू होता है।

polls आवेदन में निम्नलिखित को tests.py फ़ाइल में tests.py :

import datetime

from django.test import TestCase
from django.utils import timezone

from .models import Question


class QuestionModelTests(TestCase):

    def test_was_published_recently_with_future_question(self):
        """
        was_published_recently() returns False for questions whose pub_date
        is in the future.
        """
        time = timezone.now() + datetime.timedelta(days=30)
        future_question = Question(pub_date=time)
        self.assertIs(future_question.was_published_recently(), False)

यहाँ हमने एक django.test.TestCase उपवर्ग बनाया है django.test.TestCase भविष्य में pub_date साथ एक Question उदाहरण pub_date है। हम तो was_published_recently() के आउटपुट की जांच करते हैं - जो कि गलत होना चाहिए

परीक्षण चल रहा है

टर्मिनल में, हम अपना परीक्षण चला सकते हैं:

$ python manage.py test polls
...\> py manage.py test polls

और आप कुछ इस तरह देखेंगे:

Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test_was_published_recently_with_future_question (polls.tests.QuestionModelTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/path/to/mysite/polls/tests.py", line 16, in test_was_published_recently_with_future_question
    self.assertIs(future_question.was_published_recently(), False)
AssertionError: True is not False

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (failures=1)
Destroying test database for alias 'default'...

यह क्या हुआ:

  • polls आवेदन में परीक्षणों के लिए manage.py test polls देखा गया
  • इसमें django.test.TestCase क्लास का एक उपवर्ग मिला
  • इसने परीक्षण के उद्देश्य के लिए एक विशेष डेटाबेस बनाया
  • इसने परीक्षण विधियों की तलाश की - जिनके नाम test शुरू होते हैं
  • test_was_published_recently_with_future_question में test_was_published_recently_with_future_question एक Question उदाहरण बनाया है जिसका pub_date क्षेत्र भविष्य में 30 दिन है
  • … और assertIs() विधि का उपयोग करते हुए, यह पता चला कि इसका was_published_recently() True , हालांकि हम चाहते थे कि यह False लौटे

परीक्षण हमें सूचित करता है कि कौन सा परीक्षण विफल रहा और यहां तक ​​कि जिस लाइन पर विफलता हुई।

बग को ठीक करना

हम पहले से ही जानते हैं कि समस्या क्या है: Question.was_published_recently() यदि उसका pub_date भविष्य में है, तो उसे वापस लौटना चाहिए। मॉडल में विधि को संशोधित करें, ताकि यह केवल तभी True हो जब तिथि पूर्व में हो:

def was_published_recently(self):
    now = timezone.now()
    return now - datetime.timedelta(days=1) <= self.pub_date <= now

और परीक्षण फिर से चलाएं:

Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK
Destroying test database for alias 'default'...

बग की पहचान करने के बाद, हमने एक परीक्षण लिखा जो इसे उजागर करता है और कोड में बग को ठीक करता है ताकि हमारा परीक्षण पास हो जाए।

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

अधिक व्यापक परीक्षण

जब हम यहाँ हैं, हम आगे was_published_recently() विधि को पिन कर सकते हैं; वास्तव में, यह सकारात्मक रूप से शर्मनाक होगा यदि एक बग को ठीक करने में हमने दूसरे को पेश किया था।

विधि के व्यवहार को अधिक व्यापक रूप से जांचने के लिए एक ही कक्षा में दो और परीक्षण विधियाँ जोड़ें:

def test_was_published_recently_with_old_question(self):
    """
    was_published_recently() returns False for questions whose pub_date
    is older than 1 day.
    """
    time = timezone.now() - datetime.timedelta(days=1, seconds=1)
    old_question = Question(pub_date=time)
    self.assertIs(old_question.was_published_recently(), False)

def test_was_published_recently_with_recent_question(self):
    """
    was_published_recently() returns True for questions whose pub_date
    is within the last day.
    """
    time = timezone.now() - datetime.timedelta(hours=23, minutes=59, seconds=59)
    recent_question = Question(pub_date=time)
    self.assertIs(recent_question.was_published_recently(), True)

और अब हमारे पास तीन परीक्षण हैं जो इस बात की पुष्टि करते हैं कि Question.was_published_recently() अतीत, हाल और भविष्य के प्रश्नों के लिए समझदार मूल्य देता है।

फिर से, polls एक सरल अनुप्रयोग है, लेकिन हालांकि यह भविष्य में बढ़ता है और इसके साथ जो भी अन्य कोड इंटरैक्ट करता है, अब हमारे पास कुछ गारंटी है कि जिस विधि के लिए हमने परीक्षण लिखा है, वह अपेक्षित तरीकों से व्यवहार करेगा।

एक दृश्य का परीक्षण करें

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

एक दृश्य के लिए एक परीक्षण

जब हमने ऊपर बग को ठीक किया, तो हमने पहले परीक्षण लिखा और फिर इसे ठीक करने के लिए कोड। वास्तव में यह परीक्षण-संचालित विकास का एक सरल उदाहरण था, लेकिन यह वास्तव में कोई फर्क नहीं पड़ता कि हम किस क्रम में काम करते हैं।

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

इससे पहले कि हम कुछ भी ठीक करने की कोशिश करें, चलो हमारे निपटान में उपकरणों पर एक नज़र डालें।

Django परीक्षण ग्राहक

Django दृश्य स्तर पर कोड के साथ बातचीत करने वाले उपयोगकर्ता को अनुकरण करने के लिए एक परीक्षण Client प्रदान करता है। हम इसका उपयोग tests.py या shell में भी कर सकते हैं।

हम shell साथ फिर से शुरू करेंगे, जहां हमें कुछ चीजों को करने की जरूरत है, जो कि tests.py में जरूरी नहीं हैं। पहला shell में परीक्षण वातावरण स्थापित करना है:

$ python manage.py shell
...\> py manage.py shell
>>> from django.test.utils import setup_test_environment
>>> setup_test_environment()

setup_test_environment() एक टेम्पलेट रेंडरर स्थापित करता है जो हमें प्रतिक्रिया पर कुछ अतिरिक्त विशेषताओं की जांच करने की अनुमति देगा जैसे कि response.context जो अन्यथा उपलब्ध नहीं होगा। ध्यान दें कि यह विधि एक परीक्षण डेटाबेस को सेटअप नहीं करती है, इसलिए निम्न मौजूदा डेटाबेस के खिलाफ चलाया जाएगा और आउटपुट आपके द्वारा पहले से बनाए गए प्रश्नों के आधार पर थोड़ा भिन्न हो सकता है। यदि आपका TIME_ZONE settings.py में नहीं है तो आपको अप्रत्याशित परिणाम प्राप्त हो सकते हैं। यदि आपको इसे पहले सेट करना याद नहीं है, तो इसे जारी रखने से पहले जाँच लें।

अगला हमें परीक्षण ग्राहक वर्ग आयात करने की आवश्यकता है (बाद में tests.py हम django.test.TestCase वर्ग का उपयोग करेंगे, जो अपने स्वयं के ग्राहक के साथ आता है, इसलिए इसकी आवश्यकता नहीं होगी):

>>> from django.test import Client
>>> # create an instance of the client for our use
>>> client = Client()

उस तैयार के साथ, हम ग्राहक को हमारे लिए कुछ काम करने के लिए कह सकते हैं:

>>> # get a response from '/'
>>> response = client.get('/')
Not Found: /
>>> # we should expect a 404 from that address; if you instead see an
>>> # "Invalid HTTP_HOST header" error and a 400 response, you probably
>>> # omitted the setup_test_environment() call described earlier.
>>> response.status_code
404
>>> # on the other hand we should expect to find something at '/polls/'
>>> # we'll use 'reverse()' rather than a hardcoded URL
>>> from django.urls import reverse
>>> response = client.get(reverse('polls:index'))
>>> response.status_code
200
>>> response.content
b'\n    <ul>\n    \n        <li><a href="/polls/1/">What&#39;s up?</a></li>\n    \n    </ul>\n\n'
>>> response.context['latest_question_list']
<QuerySet [<Question: What's up?>]>

हमारे विचार में सुधार

चुनावों की सूची उन सर्वेक्षणों को दिखाती है जो अभी तक प्रकाशित नहीं हुए हैं (यानी जिनके पास भविष्य में pub_date है)। चलो ठीक करते हैं।

ट्यूटोरियल 4 में हमने ListView आधार पर एक क्लास-आधारित ListView :

class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_question_list'

    def get_queryset(self):
        """Return the last five published questions."""
        return Question.objects.order_by('-pub_date')[:5]

हमें get_queryset() विधि में संशोधन करने और इसे बदलने की आवश्यकता है ताकि यह timezone.now() साथ तुलना करके दिनांक की जांच कर सके। timezone.now() पहले हमें एक आयात जोड़ने की आवश्यकता है:

from django.utils import timezone

और फिर हमें get_queryset पद्धति में संशोधन करना चाहिए:

def get_queryset(self):
    """
    Return the last five published questions (not including those set to be
    published in the future).
    """
    return Question.objects.filter(
        pub_date__lte=timezone.now()
    ).order_by('-pub_date')[:5]

Question.objects.filter(pub_date__lte=timezone.now()) एक Question.objects.filter(pub_date__lte=timezone.now()) देता है जिसमें Question s होता है जिसका pub_date इससे कम या बराबर है - अर्थात, इससे पहले या इसके बराबर - timezone.now

हमारे नए दृष्टिकोण का परीक्षण

अब आप अपने आप को संतुष्ट कर सकते हैं कि यह अपेक्षा के अनुरूप व्यवहार करता है, जो आपके ब्राउज़र में साइट को लोड कर रहा है, अतीत और भविष्य में तारीखों के साथ Questions बना रहा है, और जाँच रहा है कि केवल जो सूचीबद्ध हैं, वे सूचीबद्ध हैं। आप ऐसा नहीं करना चाहते हैं कि हर बार जब आप कोई बदलाव करते हैं जो इसे प्रभावित कर सकता है - तो चलिए हम भी अपने ऊपर दिए गए परीक्षण के आधार पर एक परीक्षण बनाएं।

निम्नलिखित polls/tests.py :

from django.urls import reverse

और हम प्रश्न बनाने के साथ-साथ एक नई परीक्षा कक्षा के लिए एक शॉर्टकट फ़ंक्शन बनाएंगे:

def create_question(question_text, days):
    """
    Create a question with the given `question_text` and published the
    given number of `days` offset to now (negative for questions published
    in the past, positive for questions that have yet to be published).
    """
    time = timezone.now() + datetime.timedelta(days=days)
    return Question.objects.create(question_text=question_text, pub_date=time)


class QuestionIndexViewTests(TestCase):
    def test_no_questions(self):
        """
        If no questions exist, an appropriate message is displayed.
        """
        response = self.client.get(reverse('polls:index'))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "No polls are available.")
        self.assertQuerysetEqual(response.context['latest_question_list'], [])

    def test_past_question(self):
        """
        Questions with a pub_date in the past are displayed on the
        index page.
        """
        create_question(question_text="Past question.", days=-30)
        response = self.client.get(reverse('polls:index'))
        self.assertQuerysetEqual(
            response.context['latest_question_list'],
            ['<Question: Past question.>']
        )

    def test_future_question(self):
        """
        Questions with a pub_date in the future aren't displayed on
        the index page.
        """
        create_question(question_text="Future question.", days=30)
        response = self.client.get(reverse('polls:index'))
        self.assertContains(response, "No polls are available.")
        self.assertQuerysetEqual(response.context['latest_question_list'], [])

    def test_future_question_and_past_question(self):
        """
        Even if both past and future questions exist, only past questions
        are displayed.
        """
        create_question(question_text="Past question.", days=-30)
        create_question(question_text="Future question.", days=30)
        response = self.client.get(reverse('polls:index'))
        self.assertQuerysetEqual(
            response.context['latest_question_list'],
            ['<Question: Past question.>']
        )

    def test_two_past_questions(self):
        """
        The questions index page may display multiple questions.
        """
        create_question(question_text="Past question 1.", days=-30)
        create_question(question_text="Past question 2.", days=-5)
        response = self.client.get(reverse('polls:index'))
        self.assertQuerysetEqual(
            response.context['latest_question_list'],
            ['<Question: Past question 2.>', '<Question: Past question 1.>']
        )

आइए इनमें से कुछ को और करीब से देखें।

पहला सवाल बनाने की प्रक्रिया से बाहर कुछ दोहराव लेने के लिए एक प्रश्न शॉर्टकट फ़ंक्शन, create_question

test_no_questions कोई प्रश्न नहीं बनाता है, लेकिन संदेश की जाँच करता है: "कोई चुनाव उपलब्ध नहीं हैं।" और सत्यापित करता है कि latest_question_list खाली है। ध्यान दें कि django.test.TestCase वर्ग कुछ अतिरिक्त अभिकथन विधियाँ प्रदान करता है। इन उदाहरणों में, हम assertContains() और assertQuerysetEqual()

test_past_question , हम एक प्रश्न बनाते हैं और सत्यापित करते हैं कि यह सूची में दिखाई देता है।

test_future_question , हम भविष्य में pub_date के साथ एक प्रश्न बनाते हैं। डेटाबेस प्रत्येक परीक्षण विधि के लिए रीसेट है, इसलिए पहला प्रश्न अब नहीं है, और इसलिए फिर से सूचकांक में कोई प्रश्न नहीं होना चाहिए।

और इसी तरह। वास्तव में, हम साइट पर व्यवस्थापक इनपुट और उपयोगकर्ता के अनुभव की एक कहानी बताने के लिए परीक्षणों का उपयोग कर रहे हैं, और जाँच कर रहे हैं कि हर राज्य में और सिस्टम की स्थिति में हर नए परिवर्तन के लिए, अपेक्षित परिणाम प्रकाशित किए जाते हैं।

DetailView परीक्षण

हमारे पास क्या अच्छा है; हालाँकि, भले ही भविष्य के प्रश्न सूचकांक में दिखाई न दें, फिर भी उपयोगकर्ता उन तक पहुँच सकते हैं यदि उन्हें सही URL का पता है या अनुमान है। इसलिए हमें DetailView एक समान बाधा जोड़ने की आवश्यकता है:

class DetailView(generic.DetailView):
    ...
    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        return Question.objects.filter(pub_date__lte=timezone.now())

और निश्चित रूप से, हम कुछ परीक्षण जोड़ेंगे, यह जांचने के लिए कि एक Question जिसका pub_date अतीत में है, प्रदर्शित किया जा सकता है और भविष्य में pub_date साथ ऐसा नहीं है:

class QuestionDetailViewTests(TestCase):
    def test_future_question(self):
        """
        The detail view of a question with a pub_date in the future
        returns a 404 not found.
        """
        future_question = create_question(question_text='Future question.', days=5)
        url = reverse('polls:detail', args=(future_question.id,))
        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)

    def test_past_question(self):
        """
        The detail view of a question with a pub_date in the past
        displays the question's text.
        """
        past_question = create_question(question_text='Past Question.', days=-5)
        url = reverse('polls:detail', args=(past_question.id,))
        response = self.client.get(url)
        self.assertContains(response, past_question.question_text)

अधिक परीक्षणों के लिए विचार

हमें परिणाम दृश्य में एक समान get_queryset पद्धति जोड़ने और उस दृश्य के लिए एक नया परीक्षण वर्ग बनाने की आवश्यकता है। यह बहुत कुछ वैसा ही होगा जैसा हमने अभी बनाया है; वास्तव में बहुत दोहराव होगा।

हम अन्य तरीकों से भी अपने आवेदन में सुधार कर सकते हैं, रास्ते में परीक्षण जोड़ सकते हैं। उदाहरण के लिए, यह मूर्खतापूर्ण है कि Questions उस साइट पर प्रकाशित किए जा सकते हैं जिनके पास कोई Choices नहीं है। इसलिए, हमारे विचार इसके लिए जाँच कर सकते हैं, और ऐसे Questions बाहर कर सकते हैं। हमारे परीक्षण बिना Choices एक Question बनाते हैं और फिर परीक्षण करते हैं कि यह प्रकाशित नहीं हुआ है, साथ ही Question साथ एक समान Question बनाएं, और यह परीक्षण करें कि यह प्रकाशित है।

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

एक निश्चित बिंदु पर आप अपने परीक्षणों को देखने के लिए बाध्य होते हैं और आश्चर्य करते हैं कि क्या आपका कोड टेस्ट ब्लोट से पीड़ित है, जो हमें लाता है:

परीक्षण करते समय, अधिक बेहतर है

ऐसा लग सकता है कि हमारे परीक्षण नियंत्रण से बाहर हो रहे हैं। इस दर पर हमारे आवेदन की तुलना में हमारे परीक्षणों में जल्द ही अधिक कोड होंगे, और पुनरावृत्ति हमारे कोड के बाकी हिस्सों की सुरुचिपूर्ण संगति की तुलना में अनिश्चित है।

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

कभी-कभी परीक्षणों को अद्यतन करने की आवश्यकता होगी। मान लीजिए कि हम अपने विचारों में संशोधन करते हैं ताकि केवल Choices Questions प्रकाशित हों। उस स्थिति में, हमारे कई मौजूदा परीक्षण विफल हो जाएंगे - हमें यह बताना कि उन्हें आज तक लाने के लिए कौन से परीक्षणों में संशोधन करने की आवश्यकता है , इसलिए इस हद तक परीक्षण स्वयं की देखभाल करने में मदद करते हैं।

सबसे कम, जैसा कि आप विकसित करना जारी रखते हैं, आप पा सकते हैं कि आपके पास कुछ परीक्षण हैं जो अब बेमानी हैं। यहां तक ​​कि यह भी एक समस्या नहीं है; परीक्षण में अतिरेक एक अच्छी बात है।

जब तक आपके परीक्षणों को समझदारी से व्यवस्थित किया जाता है, तब तक वे असहनीय नहीं होंगे। अंगूठे के अच्छे नियमों में शामिल हैं:

  • प्रत्येक मॉडल या दृश्य के लिए एक अलग TestClass
  • शर्तों के प्रत्येक सेट के लिए एक अलग परीक्षण विधि जिसे आप परीक्षण करना चाहते हैं
  • परीक्षण विधि नाम जो उनके कार्य का वर्णन करते हैं

आगे की जांच

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

उदाहरण के लिए, जबकि हमारे परीक्षणों ने एक मॉडल के कुछ आंतरिक तर्क को कवर किया है और जिस तरह से हमारे विचार जानकारी प्रकाशित करते हैं, आप अपने HTML को ब्राउज़र में वास्तव में प्रस्तुत करने के तरीके का परीक्षण करने के लिए Selenium जैसे "इन-ब्राउज़र" ढांचे का उपयोग कर सकते हैं। ये उपकरण आपको न केवल आपके Django कोड के व्यवहार की जांच करने की अनुमति देते हैं, बल्कि उदाहरण के लिए, आपके जावास्क्रिप्ट की भी। यह देखने के लिए काफी कुछ है कि परीक्षण एक ब्राउज़र लॉन्च करते हैं, और आपकी साइट के साथ बातचीत करना शुरू करते हैं, जैसे कि एक इंसान इसे चला रहा था! Django में सेलेनियम जैसे उपकरणों के साथ एकीकरण की सुविधा के लिए LiveServerTestCase शामिल है।

यदि आपके पास एक जटिल एप्लिकेशन है, तो आप निरंतर एकीकरण के प्रयोजनों के लिए हर प्रतिबद्ध के साथ स्वचालित रूप से परीक्षण चलाना चाह सकते हैं, ताकि गुणवत्ता नियंत्रण स्वयं - कम से कम आंशिक रूप से स्वचालित हो।

अपने आवेदन के अनछुए हिस्सों को स्पॉट करने का एक अच्छा तरीका कोड कवरेज की जांच करना है। यह भी नाजुक या मृत कोड की पहचान करने में मदद करता है। यदि आप कोड के टुकड़े का परीक्षण नहीं कर सकते हैं, तो आमतौर पर इसका मतलब है कि कोड को फिर से सक्रिय या हटा दिया जाना चाहिए। कवरेज मृत कोड की पहचान करने में मदद करेगा। विवरण के लिए कवरेज थिंकपैड के साथ एकीकरण देखें।

Django में परीक्षण के परीक्षण के बारे में व्यापक जानकारी है।

आगे क्या होगा?

परीक्षण पर पूर्ण विवरण के लिए, Django में परीक्षण देखें।

जब आप Django के विचारों का परीक्षण करने में सहज हों, तो स्थैतिक फ़ाइलों के प्रबंधन के बारे में जानने के लिए इस ट्यूटोरियल के भाग 6 को पढ़ें।