Nice to meet you, everyone. I'm going to publish a memorandum of the process of creating a voting (poll) application using Django. Since I am a beginner of Qiita, please understand that some parts may be difficult to read.
series
-[Beginner] [Python / Django] A fledgling web engineer tried a Django tutorial-No. 0- -[Beginner] [Python / Django] A fledgling web engineer tried a Django tutorial-Part 1- -[Beginner] [Python / Django] A fledgling web engineer tried a Django tutorial-Part 2- -[Beginner] [Python / Django] A fledgling web engineer tried a Django tutorial-Part 3- -[Beginner] [Python / Django] A fledgling web engineer tried a Django tutorial-Part 4-
I'll write the code to use with Django's automated testing feature.
What code do you need to test Django? First, run the test interactively.
Test content: Confirm that the was_published_recently function is False when the Question pub_date is in the future date (30 days from today). Test result: FAILD (The expected behavior of was_published_recently is False, but the actual behavior is True)
(poll-HcNSSqhc) C:\django\poll>python manage.py shell
Python 3.8.6 (tags/v3.8.6:db45529, Sep 23 2020, 15:37:30) [MSC v.1927 32 bit (Intel)] on win32     
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>
>>> import datetime
>>> from django.utils import timezone
>>> from polls.models import Question
>>>
>>> future_question = Question(pub_date=timezone.now()+datetime.timedelta(days=30))
>>> future_question.was_published_recently()
True
>>>
Code this. The expected behavior in self.assertIs is False.
polls/tests.py
from django.test import TestCase
import datetime
from django.utils import timezone
from .models import Question
# Create your tests here.
class QuestionModelTests(TestCase):
    def test_was_published_recently_whit_future_question(self):
        future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
        self.assertIs(future_question.was_published_recently(), False)
Now let's run the test. Of course it's not interactive.
(poll-HcNSSqhc) C:\django\poll>python manage.py test polls
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test_was_published_recently_whit_future_question (polls.tests.QuestionModelTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\django\poll\polls\tests.py", line 13, in test_was_published_recently_whit_future_question
    self.assertIs(future_question.was_published_recently(), False)
AssertionError: True is not False
----------------------------------------------------------------------
Ran 1 test in 0.002s
FAILED (failures=1)
Destroying test database for alias 'default'...
(poll-HcNSSqhc) C:\django\poll>
It is returning FAILD firmly. (The expected behavior of was_published_recently is False, but the actual behavior is True)
Now let's debug.
polls/models.py
    def was_published_recently(self):
        return timezone.now() - datetime.timedelta(days=1) <= self.pub_date <= timezone.now()
(poll-HcNSSqhc) C:\django\poll>python manage.py test polls
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.002s
OK
Destroying test database for alias 'default'...
(poll-HcNSSqhc) C:\django\poll>
It was OK. (The expected behavior of was_published_recently is False, and the actual behavior is False.)
Let's add more test items for the same class. A limit value test item is added.
polls/tests.py
    def test_was_published_recently_with_old_question(self):
        old_question = Question(pub_date=timezone.now() - datetime.timedelta(days=1, seconds=1))
        self.assertIs(old_question.was_published_recently(), False)
    def test_was_published_recently_with_recently_question(self):
        recently_question = Question(pub_date=timezone.now(
        ) - datetime.timedelta(hours=23, minutes=59, seconds=59))
        self.assertIs(recently_question.was_published_recently(), True)
(poll-HcNSSqhc) C:\django\poll>python manage.py test polls
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
...
----------------------------------------------------------------------
Ran 3 tests in 0.004s
OK
Destroying test database for alias 'default'...
(poll-HcNSSqhc) C:\django\poll>
OK is displayed.
Use the Client class to test your views in Django. First, run the test interactively.
Test content: The view "http://127.0.0.1/polls" exists Test result: HTTP200 and content can be obtained
(poll-HcNSSqhc) C:\django\poll>python manage.py shell
Python 3.8.6 (tags/v3.8.6:db45529, Sep 23 2020, 15:37:30) [MSC v.1927 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> 
>>> 
>>> from django.test.utils import setup_test_environment
>>> setup_test_environment()  
>>> from django.test import Client
>>> from django.urls import reverse
>>> client = Client()
>>> response = client.get(reverse('polls:index'))      
>>> 
>>> response.status_code
200
>>>
>>> response.content
b'\n    <ul>\n    \n        <li><a href="/polls/5/">What's this?</a></li>\n    \n    </ul>\n'
>>>
>>> response.context['latest_question_list'] 
<QuerySet [<Question: What's this?>]>
>>>
There is a problem displaying votes that are dated in the future, so let's fix it.
Question.objects.filter () means to filter, and pub_date__lte = timezone.now () is a conditional expression whose pub_date is less than or equal to timezone.now () (less than equal).
polls/views.py
from django.utils import timezone
class IndexView(generic.ListView):
    ***
    def get_queryset(self):
        return Question.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')[:5]
Prepare the test code.
polls/tests.py
from django.urls import reverse
def create_question(question_text, days):
    time = timezone.now() + datetime.timedelta(days=days)
    return Question.objects.create(question_text=question_text, pub_date=time)
class QuestionIndexViewTest(TestCase):
    #HTTP200, screen message: No polls are available., Question list: empty
    def test_no_question(self):
        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'], [])
    #Question list: Past question.
    def test_past_question(self):
        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.>'])
    #Question list: empty(Future questions are not displayed)
    def test_feature_question(self):
        create_question(question_text="Feature question.", days=30)
        response = self.client.get(reverse('polls:index'))
        self.assertContains(response, "No polls are available.")
        self.assertQuerysetEqual(response.context['latest_question_list'], [])
    #Question list: Past question.(Future questions are not displayed)
    def test_feature_question_and_past_question(self):
        create_question(question_text="Feature question.", days=30)
        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.>'])
    #Question list: Past question1.、Past question2.
    #Note that the question list is retrieved in the order of the latest posts, so the creation order and retrieval order will be weak.
    def test_tow_past_question(self):
        create_question(question_text="Past question1.", days=-30)
        create_question(question_text="Past question2.", days=-10)
        response = self.client.get(reverse('polls:index'))
        self.assertQuerysetEqual(response.context['latest_question_list'], [
                                 '<Question: Past question2.>', '<Question: Past question1.>'])
(poll-HcNSSqhc) C:\django\poll>python manage.py test polls
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
........
----------------------------------------------------------------------
Ran 8 tests in 0.063s
OK
Destroying test database for alias 'default'...
(poll-HcNSSqhc) C:\django\poll>
OK is displayed.
The detail view is also ready to display question details for future dates, so let's fix it.
polls/views.py
class DetailView(generic.DetailView):
  ***
    def get_queryset(self):
        return Question.objects.filter(pub_date__lte=timezone.now())
polls/tests.py
class QuestionDetailViewTests(TestCase):
    def test_future_question(self):
        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):
        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)
(poll-HcNSSqhc) C:\django\poll>python manage.py test polls
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..........
----------------------------------------------------------------------
Ran 10 tests in 0.088s
OK
Destroying test database for alias 'default'...
(poll-HcNSSqhc) C:\django\poll>
That's all for today. Thank you very much.
Recommended Posts