Skip to content

Commit fc359ac

Browse files
committed
docs: Add 05-test.md
1 parent 76603b5 commit fc359ac

File tree

1 file changed

+317
-0
lines changed

1 file changed

+317
-0
lines changed

docs/05-test.md

Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
# 05. Test
2+
3+
> **테스트를 만들어야하는 이유**
4+
> - (자동화된) 테스트를 통해 시간을 절약할 수 있습니다.
5+
> - 테스트는 문제를 그저 식별하는 것이 아니라 예방합니다.
6+
> - 테스트가 코드를 더 매력적으로 만듭니다.
7+
> - 테스트는 팀이 함께 일하는 것을 돕습니다.
8+
9+
## 버그
10+
### 버그 식별하기
11+
```bash
12+
$ python manage.py shell
13+
Python 3.9.6 (tags/v3.9.6:db3ff76, Jun 28 2021, 15:26:21) [MSC v.1929 64 bit (AMD64)] on win32
14+
Type "help", "copyright", "credits" or "license" for more information.
15+
(InteractiveConsole)
16+
```
17+
```python
18+
>>> import datetime
19+
>>> from django.utils import timezone
20+
>>> from polls.models import Question
21+
>>> future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
22+
>>> future_question.was_published_recently()
23+
True
24+
```
25+
- 미래는 최근이 아닌데 최근이라고 나온다.
26+
27+
### 버그를 노출하는 테스트 만들기
28+
- AssertionError
29+
- `polls/test.py`
30+
```python
31+
import datetime
32+
33+
from django.test import TestCase
34+
from django.utils import timezone
35+
36+
from .models import Question
37+
38+
39+
class QuestionModelTests(TestCase):
40+
41+
def test_was_published_recently_with_future_question(self):
42+
"""
43+
was_published_recently() returns False for questions whose pub_date
44+
is in the future.
45+
"""
46+
time = timezone.now() + datetime.timedelta(days=30)
47+
future_question = Question(pub_date=time)
48+
self.assertIs(future_question.was_published_recently(), False)
49+
```
50+
```bash
51+
$ python manage.py test polls
52+
Creating test database for alias 'default'...
53+
System check identified no issues (0 silenced).
54+
F
55+
======================================================================
56+
FAIL: test_was_published_recently_with_future_question (polls.tests.QuestionModelTests)
57+
was_published_recently() returns False for questions whose pub_date
58+
----------------------------------------------------------------------
59+
Traceback (most recent call last):
60+
File "C:\Users\User\django-tutorial\mysite\polls\tests.py", line 18, in test_was_published_recently_with_future_question
61+
self.assertIs(future_question.was_published_recently(), False)
62+
AssertionError: True is not False
63+
64+
----------------------------------------------------------------------
65+
Ran 1 test in 0.001s
66+
67+
FAILED (failures=1)
68+
Destroying test database for alias 'default'...
69+
```
70+
71+
### 버그 수정
72+
- `polls/models.py`
73+
```python
74+
class Question(models.Model):
75+
question_text = models.CharField(max_length=200)
76+
pub_date = models.DateTimeField('date Published')
77+
78+
def __str__(self):
79+
return self.question_text
80+
81+
# def was_published_recently(self):
82+
# return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
83+
def was_published_recently(self):
84+
now = timezone.now()
85+
return now - datetime.timedelta(days=1) <= self.pub_date <= now
86+
```
87+
88+
- 테스트 다시 실행
89+
```bash
90+
$ python manage.py test polls
91+
Creating test database for alias 'default'...
92+
System check identified no issues (0 silenced).
93+
.
94+
----------------------------------------------------------------------
95+
Ran 1 test in 0.001s
96+
97+
OK
98+
Destroying test database for alias 'default'...
99+
```
100+
101+
### 테스트 메서드 추가
102+
```python
103+
class QuestionModelTests(TestCase):
104+
105+
def test_was_published_recently_with_future_question(self):
106+
"""
107+
was_published_recently() returns False for questions whose pub_date
108+
is in the future.
109+
"""
110+
time = timezone.now() + datetime.timedelta(days=30)
111+
future_question = Question(pub_date=time)
112+
113+
self.assertIs(future_question.was_published_recently(), False)
114+
115+
def test_was_published_recently_with_old_question(self):
116+
"""
117+
was_published_recently() returns False for questions whose pub_date
118+
is older than 1 day.
119+
"""
120+
time = timezone.now() - datetime.timedelta(days=1, seconds=1)
121+
old_question = Question(pub_date=time)
122+
self.assertIs(old_question.was_published_recently(), False)
123+
124+
def test_was_published_recently_with_recent_question(self):
125+
"""
126+
was_published_recently() returns True for questions whose pub_date
127+
is within the last day.
128+
"""
129+
time = timezone.now() - datetime.timedelta(hours=23, minutes=59, seconds=59)
130+
recent_question = Question(pub_date=time)
131+
self.assertIs(recent_question.was_published_recently(), True)
132+
```
133+
134+
## 뷰 테스트
135+
136+
### 테스트 클라이언트 사용하기
137+
```bash
138+
$ python manage.py shell
139+
Python 3.9.6 (tags/v3.9.6:db3ff76, Jun 28 2021, 15:26:21) [MSC v.1929 64 bit (AMD64)] on win32
140+
Type "help", "copyright", "credits" or "license" for more information.
141+
(InteractiveConsole)
142+
```
143+
```python
144+
>>> from django.test.utils import setup_test_environment
145+
>>> setup_test_environment()
146+
>>> from django.test import Client
147+
>>> client = Client()
148+
>>> response = client.get('/')
149+
Not Found: /
150+
>>> response.status_code
151+
404
152+
>>> from django.urls import reverse
153+
>>> response = client.get(reverse('polls:index'))
154+
>>> response.status_code
155+
200
156+
>>> response.content
157+
b'\n <ul>\n \n <li><a href="/polls/1/">What&#x27;s up?</a></li>\n \n </ul>\n'
158+
>>> response.context['latest_question_list']
159+
<QuerySet [<Question: What's up?>]>
160+
```
161+
162+
### 뷰 개선
163+
- 아직 개시되지 않은 설문조사 표시 수정하기
164+
- `polls/views.py`
165+
```python
166+
from django.utils import timezone
167+
168+
class IndexView(generic.ListView):
169+
template_name = 'polls/index.html'
170+
context_object_name = 'latest_question_list'
171+
172+
# def get_queryset(self):
173+
# """Return the last five published questions."""
174+
# return Question.objects.order_by('-pub_date')[:5]
175+
def get_queryset(self):
176+
"""
177+
Return the last five published questions (not including those set to be
178+
published in the future).
179+
"""
180+
return Question.objects.filter(
181+
pub_date__lte=timezone.now()
182+
).order_by('-pub_date')[:5]
183+
```
184+
185+
### 새로운 뷰 테스트
186+
- `polls/tests.py`
187+
```python
188+
def create_question(question_text, days):
189+
"""
190+
Create a question with the given `question_text` and published the
191+
given number of `days` offset to now (negative for questions published
192+
in the past, positive for questions that have yet to be published).
193+
"""
194+
time = timezone.now() + datetime.timedelta(days=days)
195+
return Question.objects.create(question_text=question_text, pub_date=time)
196+
197+
198+
class QuestionIndexViewTests(TestCase):
199+
def test_no_questions(self):
200+
"""
201+
If no questions exist, an appropriate message is displayed.
202+
"""
203+
response = self.client.get(reverse('polls:index'))
204+
self.assertEqual(response.status_code, 200)
205+
self.assertContains(response, "No polls are available.")
206+
self.assertQuerysetEqual(response.context['latest_question_list'], [])
207+
208+
def test_past_question(self):
209+
"""
210+
Questions with a pub_date in the past are displayed on the
211+
index page.
212+
"""
213+
question = create_question(question_text="Past question.", days=-30)
214+
response = self.client.get(reverse('polls:index'))
215+
self.assertQuerysetEqual(
216+
response.context['latest_question_list'],
217+
[question],
218+
)
219+
220+
def test_future_question(self):
221+
"""
222+
Questions with a pub_date in the future aren't displayed on
223+
the index page.
224+
"""
225+
create_question(question_text="Future question.", days=30)
226+
response = self.client.get(reverse('polls:index'))
227+
self.assertContains(response, "No polls are available.")
228+
self.assertQuerysetEqual(response.context['latest_question_list'], [])
229+
230+
def test_future_question_and_past_question(self):
231+
"""
232+
Even if both past and future questions exist, only past questions
233+
are displayed.
234+
"""
235+
question = create_question(question_text="Past question.", days=-30)
236+
create_question(question_text="Future question.", days=30)
237+
response = self.client.get(reverse('polls:index'))
238+
self.assertQuerysetEqual(
239+
response.context['latest_question_list'],
240+
[question],
241+
)
242+
243+
def test_two_past_questions(self):
244+
"""
245+
The questions index page may display multiple questions.
246+
"""
247+
question1 = create_question(question_text="Past question 1.", days=-30)
248+
question2 = create_question(question_text="Past question 2.", days=-5)
249+
response = self.client.get(reverse('polls:index'))
250+
self.assertQuerysetEqual(
251+
response.context['latest_question_list'],
252+
[question2, question1],
253+
)
254+
```
255+
256+
```bash
257+
$ python manage.py test polls
258+
Creating test database for alias 'default'...
259+
System check identified no issues (0 silenced).
260+
........
261+
----------------------------------------------------------------------
262+
Ran 8 tests in 0.024s
263+
264+
OK
265+
Destroying test database for alias 'default'...
266+
```
267+
268+
### DetailView 테스트
269+
- `polls/views.py`
270+
```python
271+
class DetailView(generic.DetailView):
272+
model = Question
273+
template_name = 'polls/detail.html'
274+
275+
def get_queryset(self):
276+
"""
277+
Excludes any questions that aren't published yet.
278+
"""
279+
return Question.objects.filter(pub_date__lte=timezone.now())
280+
```
281+
282+
- `polls/tests.py`
283+
```python
284+
class QuestionDetailViewTests(TestCase):
285+
def test_future_question(self):
286+
"""
287+
The detail view of a question with a pub_date in the future
288+
returns a 404 not found.
289+
"""
290+
future_question = create_question(question_text='Future question.', days=5)
291+
url = reverse('polls:detail', args=(future_question.id,))
292+
response = self.client.get(url)
293+
self.assertEqual(response.status_code, 404)
294+
295+
def test_past_question(self):
296+
"""
297+
The detail view of a question with a pub_date in the past
298+
displays the question's text.
299+
"""
300+
past_question = create_question(question_text='Past Question.', days=-5)
301+
url = reverse('polls:detail', args=(past_question.id,))
302+
response = self.client.get(url)
303+
self.assertContains(response, past_question.question_text)
304+
```
305+
```bash
306+
$ python manage.py test polls
307+
Creating test database for alias 'default'...
308+
System check identified no issues (0 silenced).
309+
..........
310+
----------------------------------------------------------------------
311+
Ran 10 tests in 0.045s
312+
313+
OK
314+
Destroying test database for alias 'default'...
315+
```
316+
317+
- 그 외 : 장고 테스트 [공식문서](https://docs.djangoproject.com/ko/3.2/topics/testing/)

0 commit comments

Comments
 (0)