본문 바로가기

Python_WEB/Django_Tutorial

[Django]Survey WEB Application Tutorial 6

1. 테스트 소개

- 테스트를 통해 시간을 절약

https://docs.djangoproject.com/ko/3.0/intro/tutorial05/#tests-will-save-you-time

 

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

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

docs.djangoproject.com

 

- 테스트는 문제를 그저 식별하는 것이 아니라 예방합니다.

https://docs.djangoproject.com/ko/3.0/intro/tutorial05/#tests-don-t-just-identify-problems-they-prevent-them

 

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

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

docs.djangoproject.com

 

- 테스트가 코드를 더 매력적으로 만듭니다.

https://docs.djangoproject.com/ko/3.0/intro/tutorial05/#tests-make-your-code-more-attractive

 

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

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

docs.djangoproject.com

 

- 테스트는 팀이 함께 일하는 것을 돕습니다.

https://docs.djangoproject.com/ko/3.0/intro/tutorial05/#tests-help-teams-work-together

 

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

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

docs.djangoproject.com

 

2. 기초 테스팅 전략

 

3. 미래의 날짜로 메소드를 실행해 버그 확인

py manage.py shell

 

import datetime
from django.utils import timezone
from polls.models import Question

# 향후 30 일 동안 pub_date로 Question 인스턴스를 만듭니다.
future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))

# 최근에 작성되었는가?
future_question.was_published_recently()

 

4. 버그를 노출하는 테스트 작성

'''
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 ()는 pub_date의 질문에 대해 False를 반환합니다.
        미래에 있습니다.
        """
        time = timezone.now() + datetime.timedelta(days=30)
        future_question = Question(pub_date=time)
        self.assertIs(future_question.was_published_recently(), False)

- pub_date를 가진 Question` 인스턴스를 생성하는 메소드를 가진 django.test.TestCase 하위 클래스를 생성했습니다. 

  그런 다음 was_published_recently()의 출력이 False가 되는지 확인한다.

 

5. 테스트 실행

py manage.py test polls

 

- manage.py test polls는 polls 애플리케이션에서 테스트를 찾습니다.


- django.test.TestCase 클래스의 서브 클래스를 찾았습니다.


- 테스트 목적으로 특별한 데이터베이스를 만들었습니다.


- 테스트 메소드 - 이름이 test로 시작하는 것들을 찾습니다.


- test_was_published_recently_with_future_question에서 pub_date 필드가 30일 미래인 Question 인스턴스를

  생성했습니다


- ... assertIs() 메소드를 사용하여, 우리가 False가 반환되기를 원함에도 불구하고 was_published_recently() 가 True를

  반환한다는 것을 발견했습니다.

 

6. 버그 수정

'''
polls/models.py
'''
def was_published_recently(self):
    now = timezone.now()
    return now - datetime.timedelta(days=1) <= self.pub_date <= now

- models.py에서 날짜가 과거에 있을 때에만 True를 반환하도록 메소드를 수정한다.

 

7. 테스트 재실행

py manage.py test polls

 

8. 포괄적 테스트

'''
polls/tests.py
'''
def test_was_published_recently_with_old_question(self):
    """
    was_published_recently ()는 pub_date의 질문에 대해 False를 반환합니다.
    1 일보다 오래되었습니다.
    """
    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 ()는 pub_date의 질문에 대해 True를 반환합니다.
    마지막 날에 있습니다.
    """
    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)

-  동일한 클래스에 두 가지 테스트 메소드를 추가

 

9. 테스트 환경 구성

py manage.py shell

 

from django.test.utils import setup_test_environment
setup_test_environment()

 

10. 테스트 클라이언트 클래스 import

from django.test import Client
# 사용할 클라이언트 인스턴스를 만듭니다.
client = Client()

 

11. 테스트

# '/'에서 응답을 받다
response = client.get('/')

 

# 그 주소에서 404를 예상해야합니다. 대신에
# "잘못된 HTTP_HOST 헤더"오류와 400 응답, 아마도
# 앞에서 설명한 setup_test_environment () 호출을 생략했습니다.
response.status_code

 

# 반면에 우리는 '/ polls /'
# 하드 코딩 된 URL 대신 'reverse ()'를 사용합니다
from django.urls import reverse
response = client.get(reverse('polls:index'))
response.status_code
response.content
response.context['latest_question_list']

 

12. views 개선

'''
polls/views.py
'''
class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_question_list'

    def get_queryset(self):
        """마지막 5 개의 게시 된 질문을 반환하십시오."""
        return Question.objects.order_by('-pub_date')[:5]

 

13. timezone.now()와 비교하여 날짜를 검사하도록 변경

'''
polls/views.py
'''
from django.utils import timezone

 

14. get_queryset 메소드를 수정

'''
polls/views.py
'''
def get_queryset(self):
    """
    마지막 5 개의 게시 된 질문을 반환합니다 (미래에 생성).
    """
    return Question.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')[:5]

- Question.objects.filter (pub_date__lte = timezone.now ())는 timezone.now보다 pub_date가 작거나 같은 

  Question을 포함하는 queryset을 반환

 

15. 새로운 뷰 테스트

'''
polls/tests.py
'''
from django.urls import reverse

 

16. 질문 생성 함수 생성

'''
polls/tests.py
'''
def create_question(question_text, days):
    """
    주어진`question_text`로 질문을 만들고
    주어진 '일수'가 현재로 오프셋 됨 (게시 된 질문에 대해 음수 임)
    과거에는 아직 발표되지 않은 질문에 긍정적입니다.
    """
    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):
        """
        질문이 없으면 적절한 메시지가 표시됩니다.
        """
        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):
        """
        과거에 pub_date가있는 질문은
        색인 페이지.
        """
        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):
        """
        앞으로 pub_date에 관한 질문은에 표시되지 않습니다
        인덱스 페이지
        """
        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):
        """
        과거와 미래의 질문이 모두 존재하더라도 과거 질문만 표시됩니다.
        """
        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):
        """
        질문 색인 페이지에 여러 질문이 표시 될 수 있습니다.
        """
        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.>']
        )

 

17. DetailViews 테스트

'''
polls/views.py
'''
class DetailView(generic.DetailView):
    ...
    def get_queryset(self):
        """
        아직 게시되지 않은 질문은 제외합니다.
        """
        return Question.objects.filter(pub_date__lte=timezone.now())

 

18. pub_date는 표시되지 않게 몇 가지 검사 추가

'''
polls/tests.py
'''
class QuestionDetailViewTests(TestCase):
    def test_future_question(self):
        """
        앞으로 pub_date가있는 질문의 상세도
        404를 찾을 수 없음을 반환합니다.
        """
        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):
        """
        과거에 pub_date가있는 질문의 상세보기
        질문의 텍스트를 표시합니다.
        """
        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)

 

19. 테스트 추가 하면 좋은 것

- 각 모델이나 뷰에 대한 별도의 TestClass

 

- 테스트하려는 각 조건 집합에 대해 분리된 테스트 방법

 

- 기능을 설명하는 테스트 메소드 이름

 

https://docs.djangoproject.com/ko/3.0/intro/tutorial05/#tests-help-teams-work-together

 

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

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

docs.djangoproject.com