5.2 Improving our view & Testing our new view

master
Jason Zhu 2020-10-20 22:43:40 +11:00
parent 7e2d0e2d46
commit 447c1a49e5
3 changed files with 214 additions and 4 deletions

View File

@ -529,3 +529,139 @@ Write more tests to make sure it's comprehensive
recent_question = Question(pub_date=time) recent_question = Question(pub_date=time)
self.assertIs(recent_question.was_published_recently(), True) self.assertIs(recent_question.was_published_recently(), True)
``` ```
### 5.2 Test a view
Target: 如果 pub_date 设置为未来某天,这应该被解释为这个问题将在所填写的时间点才被发布,而在之前是不可见的。
#### A test for a view
We use TDD (i.e. test first, then develop)
#### The Django test client
Django provides a test **Client** (a class) to simulate a user interacting with the code at the view level.
We can try it in interactive shell following the guide
#### Improving our view
Add following in `tests.py`
```python
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.>']
)
```
Testing generated
```
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
FF......
======================================================================
FAIL: test_future_question (polls.tests.QuestionIndexViewTests)
Questions with a pub_date in the future aren't displayed on
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/jason/HomeWorkstation/SynologyGiteaSpace/djangoproject/src/polls/tests.py", line 77, in test_future_question
self.assertContains(response, "No polls are available.")
File "/home/jason/miniconda3/envs/django/lib/python3.8/site-packages/django/test/testcases.py", line 470, in assertContains
self.assertTrue(real_count != 0, msg_prefix + "Couldn't find %s in response" % text_repr)
AssertionError: False is not true : Couldn't find 'No polls are available.' in response
======================================================================
FAIL: test_future_question_and_past_question (polls.tests.QuestionIndexViewTests)
Even if both past and future questions exist, only past questions
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/jason/HomeWorkstation/SynologyGiteaSpace/djangoproject/src/polls/tests.py", line 88, in test_future_question_and_past_question
self.assertQuerysetEqual(
File "/home/jason/miniconda3/envs/django/lib/python3.8/site-packages/django/test/testcases.py", line 1052, in assertQuerysetEqual
return self.assertEqual(list(items), values, msg=msg)
AssertionError: Lists differ: ['<Question: Future question.>', '<Question: Past question.>'] != ['<Question: Past question.>']
First differing element 0:
'<Question: Future question.>'
'<Question: Past question.>'
First list contains 1 additional elements.
First extra element 1:
'<Question: Past question.>'
- ['<Question: Future question.>', '<Question: Past question.>']
+ ['<Question: Past question.>']
----------------------------------------------------------------------
Ran 8 tests in 0.018s
FAILED (failures=2)
Destroying test database for alias 'default'...
```
Fix it by change `get_queryset()` method in Question. 让他它能通过将 Question 的 pub_data 属性与 timezone.now() 相比较来判断是否应该显示此 Question

View File

@ -2,6 +2,7 @@ import datetime
from django.test import TestCase from django.test import TestCase
from django.utils import timezone from django.utils import timezone
from django.urls import reverse
from .models import Question from .models import Question
@ -33,3 +34,70 @@ class QuestionModelTests(TestCase):
time = timezone.now() - datetime.timedelta(hours=23, minutes=59, seconds=59) time = timezone.now() - datetime.timedelta(hours=23, minutes=59, seconds=59)
recent_question = Question(pub_date=time) recent_question = Question(pub_date=time)
self.assertIs(recent_question.was_published_recently(), True) self.assertIs(recent_question.was_published_recently(), True)
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.>']
)

View File

@ -3,6 +3,7 @@ from django.shortcuts import render, get_object_or_404
from django.template import loader from django.template import loader
from django.urls import reverse from django.urls import reverse
from django.views import generic from django.views import generic
from django.utils import timezone
from .models import Question, Choice from .models import Question, Choice
@ -11,8 +12,13 @@ class IndexView(generic.ListView):
context_object_name = 'latest_question_list' context_object_name = 'latest_question_list'
def get_queryset(self): 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]
# return Question.objects.order_by('-pub_date')[:5]
class DetailView(generic.DetailView): class DetailView(generic.DetailView):
model = Question model = Question