[PYTHON] Django tutorial summary for beginners by beginners ⑤ (test)

Introduction

This article is a series of steps through Django's official tutorials. This time, we'll move on to the fifth article, "Creating your first Django app, part 5."

Django tutorial summary for beginners by beginners ① (project creation ~) Django tutorial summary for beginners by beginners ② (Model, Admin) Django tutorial summary for beginners by beginners ③ (View) Django tutorial summary for beginners by beginners ④ (Generic View) Django tutorial summary for beginners by beginners ⑤ (test) Django tutorial summary for beginners by beginners ⑥ (static file) Summary of Django tutorials for beginners by beginners ⑦ (Customize Admin)

Creating your first Django app, part 5

https://docs.djangoproject.com/ja/3.0/intro/tutorial05/

Creating your first test

python


>>> 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

Obviously this is incorrect as future dates are not recent. Create a test for this.

Create a test to expose a bug

By convention, tests are created in the test.py file within your application. Any name that starts with test seems to be okay.

polls/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)

I'm writing a test in a subclass that inherits from django.test.TestCase. We then verify that the output of the method was_published_recently () is False.

Run the test

You can run the test by running the following command from the terminal.

$ python manage.py test polls

Then it will be executed as follows.

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'...

Fix bugs

Go back to the definition of was_published_recently and fix it

polls/models.py


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

Now run the test again.

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'...

More comprehensive testing

Set up a more comprehensive test for was_published_recently to prevent one bug from being crushed and a new one.

polls/tests.py


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)

Test the view

Django provides a Client that allows you to simulate user interaction at the view level. You can also use this in tests.py or in shell.

Is that

Django test client

Set up a test environment with shell.

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

Install the template renderer with setup_test_environment (). This allows you to investigate some attributes on the response that could not be tested before (such as response.context).

>>> 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&#x27;s up?</a></li>\n    \n    </ul>\n\n'
>>> response.context['latest_question_list']
<QuerySet [<Question: What's up?>]>

Improve the view

Polls that haven't been published yet are now visible, so I'll fix them.

polls/views.py



from django.utils import timezone

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]

The following page was useful for pub_date__lte. Summary of how to use Django's QuerySet filter method

Test a new view

Write a test to see if this new implementation is working.

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 is a function that makes it easy to create a question.

test_no_questions does not create a Question and when the Question does not exist -The message "No polls are available." Is displayed. -The latest_question_list is empty I'm checking.

The following tests are also tested to see if the situation is expected under certain conditions. (Well, testing is like that)

Further testing

Information on other tests is summarized on the official page below. Testing in Django

Recommended Posts

Django tutorial summary for beginners by beginners ⑤ (test)
Django tutorial summary for beginners by beginners ③ (View)
Django tutorial summary for beginners by beginners ⑦ (Customize Admin)
Django tutorial summary for beginners by beginners ⑥ (static file)
Django Tutorial Summary for Beginners by Beginners (Model, Admin)
Django tutorial summary for beginners by beginners ① (project creation ~)
Django tutorial summary for beginners by beginners ④ (Generic View)
Python Django tutorial summary
Reference resource summary (for beginners)
Machine learning summary by Python beginners
[For beginners] Django -Development environment construction-
What is scraping? [Summary for beginners]
Django function-based view
Django class-based view
Django
Django tutorial summary for beginners by beginners ③ (View)
Ajax in Django (using generic class view)
Django Girls Tutorial Summary First Half
Pandas basics summary link for beginners
[Deprecated] Chainer v1.24.0 Tutorial for beginners
TensorFlow Tutorial -MNIST For ML Beginners
Django Summary
Django test
Django Summary
[Explanation for beginners] TensorFlow tutorial Deep MNIST
Linux operation for beginners Basic command summary
Django Tutorial (Blog App Creation) ④ --Unit Test
A textbook for beginners made by Python beginners
An introduction to object-oriented programming for beginners by beginners
Roadmap for beginners
Python Django Tutorial (2)
Python tutorial summary
Django 1.9 for internationalization
django tutorial memo
Python Django Tutorial (8)
Python Django Tutorial (6)
About Nim higher-order functions for Nim beginners written by Nim beginners
Django filter summary
Conducting the TensorFlow MNIST For ML Beginners Tutorial
Python Django Tutorial (7)
Python Django Tutorial (1)
Python Django tutorial tutorial
Python Django Tutorial (3)
Python Django Tutorial (4)
[Translation] NumPy Official Tutorial "NumPy: the absolute basics for beginners"
I tried the MNIST tutorial for beginners of tensorflow.
Summary of pre-processing practices for Python beginners (Pandas dataframe)
[For beginners] Django Frequently used commands and reference collection
Primality test by Python
Machine learning tutorial summary
Spacemacs settings (for beginners)
Django Polymorphic Associations Tutorial
django oscar simple tutorial
python textbook for beginners
Faker summary by language
Django Girls Tutorial Note
[Memo] Test code summary
Dijkstra algorithm for beginners
Summary for learning RAPIDS
Batch thought by beginners
OpenCV for Python beginners
Summary of test method
Test automation for work
[For beginners] Basics of Python explained by Java Gold Part 2
[Roughly translate TensorFlow Tutorial into Japanese] 1. MNIST For ML Beginners