본문 바로가기

Development (Python, Django, C..)

[Django] Tutorial 따라하기 - 5

- reference : https://docs.djangoproject.com/ko/2.1/intro/tutorial05/

 

첫 번째 장고 앱 작성하기, part 5 | Django 문서 | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.djangoproject.com

 

#. Test



-- Identify bug

(djenv) ivan@django:~/djgo$ python manage.py shell
Python 3.6.8 (default, Oct  7 2019, 12:59:55)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> import datetime
>>> from django.utils import timezone
>>> from polls.models import Question
>>> future_question = Question (pub_ate=timezone.now() + datetime.timedelta(days=30))
Traceback (most recent call last):
  File "", line 1, in 
  File "/home/ivan/djgo/djenv/lib/python3.6/site-packages/django/db/models/base.py", line 495, in __init__
    raise TypeError("'%s' is an invalid keyword argument for this function" % kwarg)
TypeError: 'pub_ate' is an invalid keyword argument for this function
>>> future_question = Question (pub_date=timezone.now() + datetime.timedelta(days=30))
>>> future_question.was_published_recently()
True

--> Not True



-- Make Test

(djenv) ivan@django:~/djgo$ more 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) 

(djenv) ivan@django:~/djgo$




-- Execute test

(djenv) ivan@django:~/djgo$ python 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 "/home/ivan/djgo/polls/tests.py", line 18, 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'...

.. assertIs() 메소드를 사용하여, 우리가 False가 반환되기를 원함에도 불구하고 was_published_recently() 가 True를 반환한다는 것을 발견했습니다.



-- Fix the bug

(djenv) ivan@django:~/djgo$ more polls/models.py

import datetime 

from django.db    import models 
from django.utils import timezone 


class Question(models.Model): 
    question_text = models.CharField    (max_length=200) 
    pub_date      = models.DateTimeField('date published') 

    def __str__(self): 
        return self.question_text 

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



class Choice(models.Model): 
    question    = models.ForeignKey  (Question, on_delete=models.CASCADE) 
    choice_text = models.CharField   (max_length=200) 
    votes       = models.IntegerField(default=0) 

    def __str__(self): 
        return self.choice_text 




-- Test again

(djenv) ivan@django:~/djgo$ python manage.py test polls
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK
Destroying test database for alias 'default'...




-- For more test

(djenv) ivan@django:~/djgo$ more 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) 




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) 






#. View test

(djenv) ivan@django:~/djgo$ python manage.py shell
Python 3.6.8 (default, Oct  7 2019, 12:59:55)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.test.utils import setup_test_environment
>>> setup_test_environment()
>>>
>>> from django.test import 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    

    \n    \n        
  • What's up?
  • \n    \n    

\n'
>>> response.context['ltest_question_list']
Traceback (most recent call last):
  File "", line 1, in 
  File "/home/ivan/djgo/djenv/lib/python3.6/site-packages/django/template/context.py", line 83, in __getitem__
    raise KeyError(key)
KeyError: 'ltest_question_list'
>>> response.context['latest_question_list']
]>





-- Improve View


(djenv) ivan@django:~/djgo$ more polls/views.py

#from django.http      import Http404 
from django.http      import HttpResponse, HttpResponseRedirect 
from django.shortcuts import render, get_object_or_404 
from django.urls      import reverse 
from django.views     import generic 
from django.utils     import timezone 
#from django.template  import loader 

from .models          import Question, Choice 


class IndexView(generic.ListView): 
    template_name = 'polls/index.html' 
    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 Question.objects.filter( 
            pub_date__lte=timezone.now() 
            ).order_by('-pub_date')[:5] 


class DetailView(generic.DetailView): 
    model = Question 
    template_name = 'polls/detail.html' 


class ResultsView(generic.DetailView): 
    model = Question 
    template_name = 'polls/results.html' 


def vote(request, question_id): 
    question = get_object_or_404(Question, pk=question_id) 
    try: 
        selected_choice = question.choice_set.get(pk=request.POST['choice']) 
    except (KeyError, Choice.DoesNotExist): 
        return render(request, 'polls/detail.html', { 
            'question': qeustion, 
            'error_message':"You didn't select a choice", 
            }) 
    else: 
        selected_choice.votes += 1 
        selected_choice.save() 
        return HttpResponseRedirect(reverse('polls:results', args=(question.id,))) 




-- New View Tesst


(djenv) ivan@django:~/djgo$ more polls/tests.py

import datetime 

from django.test  import TestCase 
from django.utils import timezone 
from django.urls  import reverse 

from .models      import Question 


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'], 
            [''] 
        ) 

    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'], 
            [''] 
        ) 

    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'], 
            ['', ''] 
        ) 

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) 




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) 


(djenv) ivan@django:~/djgo$



-- Test again 

(djenv) ivan@django:~/djgo$ python manage.py test polls
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
......
----------------------------------------------------------------------
Ran 6 tests in 0.048s

OK
Destroying test database for alias 'default'...