[Django] tutorial #5-test

์ •๋ณด๊ตฌ๋‹ˆยท2021๋…„ 11์›” 28์ผ
0

Django

๋ชฉ๋ก ๋ณด๊ธฐ
7/15
post-thumbnail

์ž‘์„ฑํ•œ ์ฝ”๋“œ๋“ค์— ๋Œ€ํ•ด ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

ํ•˜๋‚˜์˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด,
๊ฒฐ๊ณผ๊ฐ€ ์›ํ•˜๋Š” ๊ฐ’์œผ๋กœ ๋‚˜์˜ค๋Š”์ง€์— ๋Œ€ํ•ด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ๋˜๋Š” ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ์ˆ˜์‹ญ๊ฐœ์˜ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์—ฎ์ด๊ฒŒ ๋˜๋ฉด ํ•˜๋‚˜ํ•˜๋‚˜ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณผ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์‹œ๊ฐ„์„ ์ ˆ์•ฝํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ…Œ์ŠคํŠธ ์ž‘์„ฑ์„ ํ†ตํ•ด ๊ธฐ๋Šฅ์„ ๋ช…ํ™•ํžˆ ํ•ด์„œ ์•ž์œผ๋กœ ์ƒ๊ธธ ๋ฌธ์ œ๋“ค์— ๋Œ€ํ•ด ์˜ˆ๋ฐฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋งŽ์€ ์‚ฌ๋žŒ๋“ค๊ณผ ํ˜‘์—…ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ์‚ฌ๋žŒ์ด ์ˆ˜์ •ํ–ˆ์„ ๋•Œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ธฐ๋Šฅ๊ฐœ๋ฐœ์— ๋Œ€ํ•œ ์ฝ”๋“œ๋ฅผ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋จผ์ € ์ž‘์„ฑํ•˜๊ณ  ๋‚œ๋’ค, ๊ธฐ๋Šฅ๊ฐœ๋ฐœ์„ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์„ ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ(TDD)์ด๋ผ ํ•œ๋‹ค.



์ฒซ๋ฒˆ์งธ ํ…Œ์ŠคํŠธ ์ž‘์„ฑํ•˜๊ธฐ


๋ฒ„๊ทธ ์‹๋ณ„ํ•˜๊ธฐ

์ง€๊ธˆ๊นŒ์ง€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ์—๋Š” ๋ฒ„๊ทธ๊ฐ€ ์žˆ๋Š”๋ฐ,

๋ชจ๋ธ ์ฝ”๋“œ ์ค‘ ๋ฐ์ดํ„ฐ๊ฐ€ ์ตœ๊ทผ์ด๋ƒ ์•„๋‹ˆ๋ƒ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜(was_published_recently(self))์—์„œ ๋ฌธ์ œ๊ฐ€ ํ•˜๋‚˜ ์žˆ๋‹ค.

์ƒ์„ฑ๋‚ ์งœ๊ฐ€ ๋ฏธ๋ž˜์— ์ƒ์„ฑ๋œ ๋ฐ์ดํ„ฐ๋Š” ์ตœ๊ทผ์œผ๋กœ ๊ฐ„์ฃผํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋ฏธ๋ž˜์˜ ๋‚ ์งœ๋Š” ๊ฑฐ์ง“์œผ๋กœ ๋‚˜์™€์•ผํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

ํ•˜์ง€๋งŒ ์ง€๊ธˆ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ๋ฏธ๋ž˜์— ๋Œ€ํ•œ ์ฝ”๋“œ์ฒ˜๋ฆฌ๊ฐ€ ์—†๋‹ค.
๋”ฐ๋ผ์„œ shell์—์„œ ๊ฒฐ๊ณผ๊ฐ’์ด ์ฐธ์ธ์ง€ ๊ฑฐ์ง“์ธ์ง€ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

py manage.py shell

>>> import datetime
>>> from django.utils import timezone
>>> from polls.models import Question
>>> future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
>>> future_question.was_published_recently()
True

ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ๊ด€๋ จ ํŒจํ‚ค์ง€๋“ค์„ importํ•˜๊ณ 
ํ˜„์žฌ๋‚ ์งœ์— 30์ผ์„ ๋”ํ•œ ๋ฏธ๋ž˜์˜ ์ƒ์„ฑ๋‚ ์งœ๋ฅผ ๊ฐ€์ง„ ์งˆ๋ฌธ(question)์„ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด์ค€๋‹ค.

๋‹ค์Œ ์ด๊ฒƒ์ด ์ตœ๊ทผ ์ƒ์„ฑ๋‚ ์งœ์ธ์ง€ ๋ฌป๋Š” ์‹๋ณ„ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์˜€์„ ๋•Œ, ๊ฒฐ๊ณผ ๊ฐ’์ด True๊ฐ€ ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฏธ๋ž˜๋Š” ์ตœ๊ทผ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์€ ์ž˜๋ชป๋œ ๊ฒƒ์ด๋‹ค.



๋ฒ„๊ทธ๋ฅผ ๋…ธ์ถœํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๋งŒ๋“ค๊ธฐ

์ด๋Ÿฌํ•œ ํ…Œ์ŠคํŠธ๋ฅผ shell์—์„œ ์ˆ˜๋™์ ์œผ๋กœ ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ๋ช…๋ น์–ด ํ•˜๋‚˜๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณผ ์ˆ˜ ์žˆ๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณผ ๊ฒƒ์ด๋‹ค.

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์•ฑ ๋‚ด๋ถ€์˜ polls/tests.py์— ์ž‘์„ฑํ•œ๋‹ค.
์ฝ”๋“œ ์ž‘์„ฑ์‹œ ํ•จ์ˆ˜ ์ด๋ฆ„์˜ ์•ž๊ธ€์ž๋„ test๋กœ ์‹œ์ž‘ํ•ด์ฃผ๋ฉด,
๋ช…๋ น์–ด ์‹คํ–‰์‹œ ์ž‘์„ฑํ•œ test ์ฝ”๋“œ๋“ค์„ ์ฐพ์•„์„œ ์ˆ˜ํ–‰ํ•ด์ค€๋‹ค.

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

์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด,
์œ„ shell์—์„œ ํ•ด์ค€ ๊ฒƒ๊ณผ ๋น„์Šทํ•˜๋‹ค. 30์ผ ๋ฏธ๋ž˜์˜ ์งˆ๋ฌธ์„ ์ƒ์„ฑํ•œ๋’ค, ์ด ์งˆ๋ฌธ์— ๋Œ€ํ•ด ์ƒ์„ฑ์ผ์ด ์ตœ๊ทผ์ด๋ƒ๊ณ  ๋ฌผ์—ˆ์„๋•Œ ๊ฒฐ๊ณผ๊ฐ’์ด False๊ฐ€ ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด๋‹ค.



ํ…Œ์ŠคํŠธ ์‹คํ–‰

๊ทธ๋Ÿผ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์˜ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด ๋ณด๊ฒ ๋‹ค.

ํ„ฐ๋ฏธ๋„์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

py manage.py test polls

๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋‹ค์Œ๊ณผ๊ฐ™์ด ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํŒจํ–ˆ๋‹ค๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜จ๋‹ค.

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

ํ…Œ์ŠคํŠธ ์ƒ์—์„œ ๊ฒฐ๊ณผ๊ฐ’์ด False๊ฐ€ ๋‚˜์™€์•ผ ํ•˜๋Š”๋ฐ True๊ฐ€ ๋‚˜์™€ ํ…Œ์ŠคํŠธ์— ์‹คํŒจํ–ˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.



๋ฒ„๊ทธ ์ˆ˜์ •

๊ทธ๋Ÿผ ์ด์ œ ํ…Œ์ŠคํŠธ๊ฐ€ ํ†ต๊ณผ๋  ์ˆ˜ ์žˆ๋„๋ก ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •์„ ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

- polls/models.py

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

question์˜ ์ƒ์„ฑ๋‚ ์งœ๊ฐ€ ๋ฏธ๋ž˜๋กœ ๋„˜์–ด๊ฐ€์ง€ ์•Š๋„๋ก
์ตœ๊ทผ์˜ ๊ธฐ์ค€์„ ํ˜„์žฌ๋‚ ์งœ๋ฅผ ๋‘๊ณ  ํ•˜๋ฃจ๋กœ ์žก์•„๋‘์—ˆ๋‹ค.

์ˆ˜์ •์„ ํ•ด์ค€๋’ค ๋‹ค์‹œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด๋ณด๊ฒ ๋‹ค.

py manage.py test polls

๊ทธ๋Ÿผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•ด์ค€ ์ฝ”๋“œ๊ฐ€ ํ…Œ์ŠคํŠธ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ํ†ต๊ณผํ–ˆ์Œ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค

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



๋ณด๋‹ค ํฌ๊ด„์ ์ธ ํ…Œ์ŠคํŠธ ๋งŒ๋“ค๊ธฐ

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ๊ธฐ๋Šฅ์„ ๋”์šฑ ๋ช…ํ™•ํžˆ ํ•˜๊ธฐ ์œ„ํ•ด ๋ณด๋‹ค ํฌ๊ด„์ ์ธ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด 1์ผ์ด ๋„˜์–ด๊ฐˆ๋•Œ์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ๊ฐ’์ด False๊ฐ€ ๋‚˜์˜ค๊ณ 
1์ผ์ด ๋„˜์–ด๊ฐ€์ง€ ์•Š์•˜์„๋•Œ์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ๊ฐ’์ด True๊ฐ€ ๋‚˜์˜ค๋„๋ก ๊ฒ€์ฆ์„ ํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

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

์ด๋ ‡๊ฒŒ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์— ๋Œ€ํ•˜์—ฌ ์ตœ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ถฉ๋ถ„ํ•˜๊ฒŒ ์ž‘์„ฑํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค



๋ทฐ ํ…Œ์ŠคํŠธ


ํ•จ์ˆ˜์˜ ๊ธฐ๋Šฅ์ ์ธ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ–ˆ์œผ๋ฉด, ๋ทฐ๊ฐ€ ๋™์ž‘์„ ์ž˜ํ•˜๋Š”์ง€ ๋ทฐ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค.

๋ทฐ ํ…Œ์ŠคํŠธ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋œ๊ฒƒ์ฒ˜๋Ÿผ request(์š”์ฒญ)์„ ํ•˜๊ณ  response๋ฅผ ๋ฐ›์•„ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ›์•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด๋‹ค.


์žฅ๊ณ  ํ…Œ์ŠคํŠธ ํด๋ผ์ด์–ธํŠธ

์žฅ๊ณ ๋Š” ์‚ฌ์šฉ์ž๋ฅผ ์‹œ๋ฎฌ๋ ˆ์ดํŠธํ•˜๊ธฐ ์œ„ํ•ด ํ…Œ์ŠคํŠธ ํด๋ผ์ด์–ธํŠธ ํด๋ž˜์Šค์ธ Client๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

์ด ํ…Œ์ŠคํŠธ ํด๋ผ์ด์–ธํŠธ๋Š” tests.py ๋˜๋Š” shell์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค

py manage.py shell

ํ˜„์žฌ ์‚ฌ์šฉ์ค‘์ธ DB๋ฐ์ดํ„ฐ๋ฅผ ์ด์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด setup_test_environment๋ผ๋Š” ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•ด์ค€๋‹ค.

>>> from django.test.utils import setup_test_environment
>>> setup_test_environment()

๋‹ค์Œ์œผ๋กœ ํ…Œ์ŠคํŠธ ํด๋ผ์ด์–ธํŠธ ํด๋ž˜์Šค์ธ Client๋ฅผ importํ•ด์ค€๋‹ค.
์ด๋•Œ client๊ฐ€ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—์„œ ์‚ฌ์šฉ์ž ์—ญํ• ์„ ํ•œ๋‹ค.

>>> from django.test import Client
>>> # create an instance of the client for our use
>>> client = Client()

๊ทธ๋Ÿผ ์ด์ œ client๊ฐ€ ์›นํŽ˜์ด์ง€๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ํ•œ๋‹ค.

>>> response = client.get('/')
Not Found: /
>>> response.status_code
404
>>> 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?>]>

์ฝ”๋“œ๋ฅผ ํ•ด์„ํ•ด๋ณด์ž๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • response = client.get('/') : ์กฐํšŒ๋ฅผ ์œ„ํ•ด ์š”์ฒญํ•˜๋Š” ๋ฐฉ์‹์ธ get์„ ํ†ตํ•ด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์›นํŽ˜์ด์ง€๋ฅผ ํ˜ธ์ถœ
  • response.status_code : ์ƒํƒœ์ฝ”๋“œ(status_code) ์„œ๋ฒ„์—์„œ ์‘๋‹ต์— ๋Œ€ํ•œ ์ƒํƒœ๋ฅผ ์ฝ”๋“œ๋กœ ์ „๋‹ฌ, ์„ฑ๊ณตํ•˜๋ฉด 200์„ ๋ฐ˜ํ™˜
  • response = client.get(reverse('polls:index')) : ํ…Œ์ŠคํŠธ ํด๋ผ์ด์–ธํŠธ๊ฐ€ polls ์•ฑ์˜ index๋ฅผ get๋ฐฉ์‹์œผ๋กœ ํ˜ธ์ถœํ•˜์—ฌ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ˜ํ™˜
  • response.status_code : ๊ฒฐ๊ณผ๊ฐ’์˜ ์ƒํƒœ์ฝ”๋“œ ๋ฐ˜ํ™˜
  • response.content : ๊ฒฐ๊ณผ๊ฐ’์˜ content๋ฅผ ๋ฐ˜ํ™˜
  • response.context['latest_question_list'] : ๊ฒฐ๊ณผ๊ฐ’์˜ context๋ฅผ ๋ฐ˜ํ™˜

์ด๋ ‡๊ฒŒ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด์„œ response๊ฐ’์ด ์›ํ•˜๋Š” ๊ฐ’์ด ๋‚˜์˜ค๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.



๋ทฐ ๊ฐœ์„ ์‹œํ‚ค๊ธฐ

์•„์ง question ๋ชฉ๋ก(ListView)์—๋Š” ๋ฏธ๋ž˜์˜ ์ƒ์„ฑ๋‚ ์งœ๊ฐ€ ์žˆ๋Š” question์ด ํ‘œ์‹œ๋œ๋‹ค. ์ด๊ฒƒ์„ ์ˆ˜์ •ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

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

์—ฌ๊ธฐ์„œ __lte๋Š” less than equal๋กœ ์žฅ๊ณ ์—์„œ ์ œ๊ณตํ•˜๋Š” ํ•„ํ„ฐ์กฐ๊ฑด์ด๋‹ค.
ํ•„ํ„ฐ๋ง์„ ํ†ตํ•ด ํ˜„์žฌ๋‚ ์งœ๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋œ๋‹ค.



๋ทฐ ํ…Œ์ŠคํŠธ ๋งŒ๋“ค๊ธฐ

์ด์ œ shell์ด ์•„๋‹Œ ์‹ค์ œ๋กœ ๋ทฐ ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

polls/test.py์— ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

- polls/test.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.
        """
        question = create_question(question_text="Past question.", days=-30)
        response = self.client.get(reverse('polls:index'))
        self.assertQuerysetEqual(
            response.context['latest_question_list'],
            [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.
        """
        question = 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],
        )

    def test_two_past_questions(self):
        """
        The questions index page may display multiple questions.
        """
        question1 = create_question(question_text="Past question 1.", days=-30)
        question2 = create_question(question_text="Past question 2.", days=-5)
        response = self.client.get(reverse('polls:index'))
        self.assertQuerysetEqual(
            response.context['latest_question_list'],
            [question2, question1],
        )

๊ฐ ํ…Œ์ŠคํŠธ์ผ€์ด์Šค๋ฅผ ์ž์„ธํžˆ ์‚ดํŽด๋ณด์ž๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค

  • test_no_questions
    ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ๋ฅผ ํ…Œ์ŠคํŠธ ํ•˜๋ฉฐ, ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ ํˆฌํ‘œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค ๋ผ๋Š” ๋ฉ”์‹œ์ง€ ๋ฐ latest_question_list๊ฐ€ ๋น„์–ด ์žˆ์Œ์„ ํ™•์ธํ•œ๋‹ค.

  • test_past_question
    ๋ฐ์ดํ„ฐ๊ฐ€ ๊ณผ๊ฑฐ์ธ ๊ฒฝ์šฐ๋ฅผ ํ…Œ์ŠคํŠธํ•œ๋‹ค.
    ๊ณผ๊ฑฐ๋ฐ์ดํ„ฐ๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค๊ณ  ํ˜ธ์ถœํ•ด์ค€ ๋’ค ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚˜์˜ค๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

  • test_future_question
    ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฏธ๋ž˜์ธ ๊ฒฝ์šฐ๋ฅผ ํ…Œ์ŠคํŠธํ•œ๋‹ค.
    ๋ฏธ๋ž˜๋ฐ์ดํ„ฐ๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค๊ณ  ๋ฐ์ดํ„ฐ๊ฐ€ ์•ˆ๋‚˜์˜ค๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

  • test_future_question_and_past_question
    ๊ณผ๊ฑฐ๋ฐ์ดํ„ฐ, ๋ฏธ๋ž˜๋ฐ์ดํ„ฐ ํ•˜๋‚˜์”ฉ ๋งŒ๋“ค๊ณ  ๊ณผ๊ฑฐ๋ฐ์ดํ„ฐ๋งŒ ๋‚˜์˜ค๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

  • test_two_past_questions
    ๊ณผ๊ฑฐ๋ฐ์ดํ„ฐ ๋‘๊ฐœ๋ฅผ ๋งŒ๋“ค๊ณ  ๋‘๊ฐœ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์ž˜ ๋‚˜์˜ค๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.



Detail ๋ทฐ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€ํ•˜๊ธฐ

๋ฏธ๋ž˜์˜ question๋“ค์ด ๋ชฉ๋ก์— ๋‚˜ํƒ€๋‚˜์ง€ ์•Š์ง€๋งŒ, ์‚ฌ์šฉ์ž๊ฐ€ url์„ ์•Œ๊ณ  ์žˆ๊ฑฐ๋‚˜, ์ถ”์ธกํ•˜๋ฉด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— detailview์— ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

- polls/views.py

class DetailView(generic.DetailView):
    ...
    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        return Question.objects.filter(pub_date__lte=timezone.now())

- polls/tests.py

class QuestionDetailViewTests(TestCase):
    def test_future_question(self):
        """
        The detail view of a question with a pub_date in the future
        returns a 404 not found.
        """
        future_question = create_question(question_text='Future question.', days=5)
        url = reverse('polls:detail', args=(future_question.id,))
        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)

    def test_past_question(self):
        """
        The detail view of a question with a pub_date in the past
        displays the question's text.
        """
        past_question = create_question(question_text='Past Question.', days=-5)
        url = reverse('polls:detail', args=(past_question.id,))
        response = self.client.get(url)
        self.assertContains(response, past_question.question_text)



๐Ÿ”Ž ์ฐธ๊ณ 
๋””์žฅ๊ณ  ๊ณต์‹๋ฌธ์„œ
๋””์žฅ๊ณ  ๊ณต์‹๋ฌธ์„œ ๊ฐ•์˜์ž๋ฃŒ

0๊ฐœ์˜ ๋Œ“๊ธ€