관리 메뉴

Storage Gonie

35. (app2) view 및 템플릿 테스트하기 본문

웹개발/Django 웹서비스 개발(인프런)

35. (app2) view 및 템플릿 테스트하기

Storage Gonie 2019. 2. 20. 10:22
반응형

***python manage.py test polls 명령어로 테스트를 실행하면 메소드별로 테스트 비어있는 DB가 생성되며 이는 실행종료시 같이 삭제된다. 따라서 각 메소드는 서로 영향을 받지 않는다.***


1. 테스트 전, 쉘에서 확인한 뒤 실제 코드를 작성할 것임.(쉘에서는 따로 비어있는 DB가 생성되는게 아니란 느낌.)

-"python manage.py shell"

-"from django.test.utils import setup_test_environment"

-"setup_test_environment"                                                 # 테스트 하기 전에 미리 수행하는 함수라고 생각하면됨.


-"from django.test import Client"

-"c = Client()"                                                                     # 클라이언트 객체 생성

-"c"                                                                                     # <django.test.client.Client object at 0x105a037b8>

"from django.urls import reverse"                    # urls.py 파일로부터 진짜 url을 가져올 때 사용함.  reverse(namespace : url name, 파라미터)

"reverse('polls:index')"                                     # '/polls/'     app_namespace : url name

"reverse('polls:results', kwargs={'pk' : 10})"     # '/polls/10/results/'

"res = c.get(reverse('polls:index'))"                   # 클라이언트 객체를 이용해 HTTP GET 메소드를 호출할 수 있다.

"res.status_code"                                                # 200 (요청결과 코드)

"res.content"                                                      # http response에서 중요한 body부분

"str(res.content, 'utf-8')"                                    # utf-8로 인코딩하여 글자 그대로 볼 수 있게 함

"res.context"                                                 # 이것을 포함한 두 코드는 내가 실습 시 작동하지 않았는데 이유는 모르겠다.

"res.context['latest_question_list']"               # views.py의 IndexView 클래스에서 context_object_name으로 지정한 이름을 인자로 넣을 수 있고 그에대한 쿼리셋이 넘어옴.


2. 실제 테스트 코드 작성

- tests.py에 reverse 모듈을 import 해준다.

- create_question함수는 그냥 클래스 내부에서 사용되는 것을 선언해준 것이다. 

- 테스트 함수인 test_index_view_with_future_question 를 작성해준다.이후 테스트를 실행한 결과를 확인한다. "python manage.py test polls"

- 결과를 살펴보면 18번째 라인 self.assertQuerysetEqual()에서 문제가 있다고 나옴, 쿼리셋의 결과가 [] 이어야 하는데 Question 객체가 들어있음.

- 여기서 쿼리셋의 결과에 1개의 객체만 들어있는 이유는 테스트 실행시 테스트 DB에서 실행되기 때문에 그러하다는 것을 알자.

- 'latest_question_list'에 미래의 날짜를 가지는 객체는 안들어오게 만들고 싶은 상태이며 IndexView클래스 내의 get_queryset메소드를 수정해준다.

- 이후 다시 테스트를 실행한 결과를 확인한다. "python manage.py test polls"

from django.urls import reverse

def create_question(question_text, days):
time = timezone.now() + datetime.timedelta(days=days)
return Question.objects.create(question_text=question_text, pub_date = time)

class QuestionViewTests1(TestCase):
def test_index_view_with_future_question(self):
create_question(question_text='Future question', days=30)
response = self.client.get(reverse('polls:index'))
self.assertEqual(response.status_code, 200) # 상태코드가 200이야?
self.assertQuerysetEqual(response.context['latest_question_list'], []) # 쿼리셋 결과가 []이야?


from django.utils import timezone

class IndexView(generic.ListView): # 객체를 리스트 형태로 전달하기 때문에 ListView 선택
#어떤 템플릿이랑 연결할 것이고, 가져온 오브젝트를 어느 이름으로 mapping 시킬것인지.
template_name = 'polls/index.html'
context_object_name = 'latest_question_list' # index.html에서 이 이름으로 변수에 접근 가능
# 오브젝트 가져오기
def get_queryset(self):
return Question.objects.order_by('-pub_date')[:5]

class IndexView(generic.ListView):   # 객체를 리스트 형태로 전달하기 때문에 ListView 선택
#어떤 템플릿이랑 연결할 것이고, 가져온 오브젝트를 어느 이름으로 mapping 시킬것인지.
template_name = 'polls/index.html'
context_object_name = 'latest_question_list' # index.html에서 이 이름으로 변수에 접근 가능
# 오브젝트 가져오기
def get_queryset(self):
return Question.objects.filter(
pub_date__lte=timezone.now() # pub_date가 현재시간보다 작은것만 필터링. 여기서 lte는 less than equal
).order_by('-pub_date')[:5]

3. tests.py에 아래의 클래스 및 메소드를 생성해 최종적으로 테스트를 마친다.

class QuestionViewTests2(TestCase):
# 아무 객체도 없는경우 아무것도 안보여줌을 테스트.
def test_index_view_with_no_questions(self):
"""
If no questions exist, an appropriate message should be displayed.
"""
response = self.client.get(reverse('polls:index'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "No polls are available.") # 아무것도 없는경우 "No polls..."가 찍여야 함(index.html참고)
self.assertQuerysetEqual(response.context['latest_question_list'], [])

# 과거의 날짜를 가진 객체는 보여짐을 테스트.
def test_index_view_with_a_past_question(self):
"""
Questions with a pub_date in the past should be 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_index_view_with_a_future_question(self):
"""
Questions with a pub_date in the future should not be 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_index_view_with_future_question_and_past_question(self):
"""
Even if both past and future questions exist, only past questions
should be 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.>']
)
# 2개의 과거 날짜를 가진 객체가 있을 때 둘 다 보여지며, 시간순서대로 잘 정렬되어 나오는지 테스트.
def test_index_view_with_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.>']
)


반응형
Comments