Closed8

Djangoのチュートリアルをなぞってみる その7:テスト

suzuki-navisuzuki-navi

テストコードを書いてみる。

diff --git a/mysite/polls/tests.py b/mysite/polls/tests.py
index 7ce503c..1179e3f 100644
--- a/mysite/polls/tests.py
+++ b/mysite/polls/tests.py
@@ -1,3 +1,17 @@
+import datetime
+
 from django.test import TestCase
+from django.utils import timezone
+
+from .models import Question
+

-# Create your tests here.
+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)
suzuki-navisuzuki-navi

python manage.py testコマンドでテストが実行できる。

$ python manage.py test polls
Found 1 test(s).
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.test_was_published_recently_with_future_question)
was_published_recently() returns False for questions whose pub_date
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/ubuntu/django-tutorial/mysite/polls/tests.py", line 17, 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'...
suzuki-navisuzuki-navi

tests.pyのファイル名を変えてみたけど、同じようにテストが実行できた。pollsディレクトリの中からテストケースを探してくれるようだ。

suzuki-navisuzuki-navi

ディレクトリを掘って中に入れてみたら、ダメだった。pollsディレクトリ直下に必要みたい。

suzuki-navisuzuki-navi

テストケースのファイルをコピーして2つにしたら、2つとも実行された。

$ python manage.py test polls
Found 2 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
FF
======================================================================
FAIL: test_was_published_recently_with_future_question (polls.tests.QuestionModelTests.test_was_published_recently_with_future_question)
was_published_recently() returns False for questions whose pub_date
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/ubuntu/django-tutorial/mysite/polls/tests.py", line 17, in test_was_published_recently_with_future_question
    self.assertIs(future_question.was_published_recently(), False)
AssertionError: True is not False

======================================================================
FAIL: test_was_published_recently_with_future_question (polls.tests2.QuestionModelTests.test_was_published_recently_with_future_question)
was_published_recently() returns False for questions whose pub_date
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/ubuntu/django-tutorial/mysite/polls/tests2.py", line 17, in test_was_published_recently_with_future_question
    self.assertIs(future_question.was_published_recently(), False)
AssertionError: True is not False

----------------------------------------------------------------------
Ran 2 tests in 0.002s

FAILED (failures=2)
Destroying test database for alias 'default'...
suzuki-navisuzuki-navi

テストに成功した時の出力例

$ python manage.py test polls
Found 1 test(s).
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'...
suzuki-navisuzuki-navi

次はViewのテストコード。

テストコードに以下のコード断片を追加。

from django.utils import timezone
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_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"], [])

viewのindexのバグ修正

diff --git a/mysite/polls/views.py b/mysite/polls/views.py
index a6a34e6..3da039b 100644
--- a/mysite/polls/views.py
+++ b/mysite/polls/views.py
@@ -2,6 +2,7 @@ from django.http import HttpResponse, Http404, HttpResponseRedirect
 from django.shortcuts import get_object_or_404, render
 from django.template import loader
 from django.urls import reverse
+from django.utils import timezone
 from django.views import generic

 from .models import Question, Choice
@@ -11,8 +12,13 @@ class IndexView(generic.ListView):
     context_object_name = "latest_question_list"

     def get_queryset(self):
-        """Return the last five published questions."""
-        return Question.objects.order_by("-pub_date")[:5]
+        """
+        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
+        ]

 def detail(request, question_id):
     try:

これでテストが成功する。self.assertContains(response, "No polls are available.")が成功する。テスト実行時はSQLiteの中のデータは関係なく、空の状態から実行されるみたいだ。

このスクラップは2023/08/09にクローズされました