Skip to content

Commit 3802503

Browse files
committed
Add tests during Django Tutorial Part 5
1 parent 75d863b commit 3802503

File tree

3 files changed

+158
-3
lines changed

3 files changed

+158
-3
lines changed

mysite/polls/models.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ def __str__(self):
2020
return self.question_text
2121

2222
def was_published_recently(self):
23-
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
23+
now = timezone.now()
24+
return now - datetime.timedelta(days=1) <= self.pub_date <= now
2425

2526

2627
class Choice(models.Model):

mysite/polls/tests.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,142 @@
1+
import datetime
2+
13
from django.test import TestCase
4+
from django.utils import timezone
5+
from django.urls import reverse
6+
7+
from .models import Question
28

39
# Create your tests here.
10+
# Rules-of-thumb for tests:
11+
# * have a separate TestClass for each model or view
12+
# * have a separate test method for each set of conditions you want to test
13+
# * use test method names that describe their function
14+
15+
16+
def create_question(question_text, days):
17+
"""
18+
Create a question with the given 'question_text' and published the
19+
given number of 'days' offset to now (negative for questions published
20+
in the past, positive for questions that have yet to be published).
21+
"""
22+
time = timezone.now() + datetime.timedelta(days=days)
23+
return Question.objects.create(question_text=question_text, pub_date=time)
24+
25+
26+
class QuestionModelTests(TestCase):
27+
# Django auto-detects test methods by looking
28+
# for methods starting with "test"
29+
def test_was_published_recently_with_future_question(self):
30+
"""
31+
was_published_recently() returns False for questions whose pub_date
32+
is in the future.
33+
"""
34+
time = timezone.now() + datetime.timedelta(days=30)
35+
future_question = Question(pub_date=time)
36+
37+
self.assertIs(future_question.was_published_recently(), False)
38+
39+
def test_was_published_recently_with_old_question(self):
40+
"""
41+
was_published_recently() returns False for questions whose pub_date
42+
is older than 1 day.
43+
"""
44+
time = timezone.now() - datetime.timedelta(days=1, seconds=1)
45+
old_question = Question(pub_date=time)
46+
47+
self.assertIs(old_question.was_published_recently(), False)
48+
49+
def test_was_published_recently_with_recent_question(self):
50+
"""
51+
was_published_recently() returns True for questions whose pub_date
52+
is within the last day.
53+
"""
54+
time = timezone.now() - datetime.timedelta(hours=23, minutes=59, seconds=59)
55+
recent_question = Question(pub_date=time)
56+
57+
self.assertIs(recent_question.was_published_recently(), True)
58+
59+
60+
class QuestionIndexViewTests(TestCase):
61+
def test_no_questions(self):
62+
"""
63+
If no questions exist, an appropriate message is displayed.
64+
"""
65+
expected_result = "No polls are available."
66+
response = self.client.get(reverse("polls:index"))
67+
self.assertEqual(response.status_code, 200)
68+
self.assertContains(response, expected_result)
69+
self.assertQuerysetEqual(response.context["latest_question_list"], [])
70+
71+
def test_past_question(self):
72+
"""
73+
Questions with a pub_date in the past are displayed on the
74+
index page.
75+
"""
76+
expected_result = ["<Question: Past Question.>"]
77+
create_question(question_text="Past Question.", days=-30)
78+
response = self.client.get(reverse("polls:index"))
79+
self.assertQuerysetEqual(
80+
response.context["latest_question_list"], expected_result
81+
)
82+
83+
def test_future_question(self):
84+
"""
85+
Questions with a pub_date in the future aren't displayed on
86+
the index page.
87+
"""
88+
expected_result = "No polls are available."
89+
create_question(question_text="Future Question.", days=30)
90+
response = self.client.get(reverse("polls:index"))
91+
self.assertContains(response, expected_result)
92+
self.assertQuerysetEqual(response.context["latest_question_list"], [])
93+
94+
def test_future_question_and_past_question(self):
95+
"""
96+
Even if both past and future questions exist, only past questions
97+
are displayed.
98+
"""
99+
expected_result = ["<Question: Past Question.>"]
100+
create_question(question_text="Past Question.", days=-30)
101+
create_question(question_text="Future Question.", days=30)
102+
response = self.client.get(reverse("polls:index"))
103+
self.assertQuerysetEqual(
104+
response.context["latest_question_list"], expected_result
105+
)
106+
107+
def test_two_past_questions(self):
108+
"""
109+
The questions index page may display multiple questions.
110+
"""
111+
expected_result = [
112+
"<Question: Past Question 2.>",
113+
"<Question: Past Question 1.>",
114+
]
115+
create_question(question_text="Past Question 1.", days=-30)
116+
create_question(question_text="Past Question 2.", days=-5)
117+
response = self.client.get(reverse("polls:index"))
118+
self.assertQuerysetEqual(
119+
response.context["latest_question_list"], expected_result
120+
)
121+
122+
123+
class QuestionDetailViewTests(TestCase):
124+
def test_future_question(self):
125+
"""
126+
The detail view of a question with a pub_date in the future
127+
returns a 404 not found.
128+
"""
129+
future_question = create_question(question_text="Future Question.", days=5)
130+
url = reverse("polls:detail", args=(future_question.id))
131+
response = self.client.get(url)
132+
self.assertEqual(response.status_code, 404)
133+
134+
def test_past_question(self):
135+
"""
136+
The detail view of a question with a pub_date in the past
137+
displays the question's text.
138+
"""
139+
past_question = create_question(question_text="Past Question.", days=-5)
140+
url = reverse("polls:detail", args=(past_question.id))
141+
response = self.client.get(url)
142+
self.assertContains(response, past_question.question_text)

mysite/polls/views.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from django.http import HttpResponseRedirect
66
from django.urls import reverse
77
from django.views import generic
8+
from django.utils import timezone
89

910
from .models import Choice, Question
1011

@@ -18,8 +19,16 @@ class IndexView(generic.ListView):
1819
context_object_name = "latest_question_list"
1920

2021
def get_queryset(self):
21-
"""Return the last five pulished questions."""
22-
return Question.objects.order_by("-pub_date")[:5]
22+
"""
23+
Return the last five pulished questions (not
24+
including those set to be published in the
25+
future).
26+
"""
27+
now = timezone.now()
28+
order = "-pub_date"
29+
# __lte filters for pub_date less than or equal
30+
# to the provided value
31+
return Question.objects.filter(pub_date__lte=now).order_by(order)[:5]
2332

2433

2534
class DetailView(generic.DetailView):
@@ -28,6 +37,12 @@ class DetailView(generic.DetailView):
2837
# generic, default is <app name>/<model name>_detail.html
2938
template_name = "polls/detail.html"
3039

40+
def get_queryset(self):
41+
"""
42+
Excludes any questions that aren't published yet.
43+
"""
44+
return Question.objects.filter(pub_date__lte=timezone.now())
45+
3146

3247
class ResultsView(generic.DetailView):
3348
model = Question

0 commit comments

Comments
 (0)