백엔드/Django

[Django] Document 따라 읽기(7) - View 테스트

안용감한호랑이 2023. 11. 14. 22:12

 

[백엔드/Django] - [Django] Document 따라 읽기(6) - Model 테스트

 

[Django] Document 따라 읽기(6) - Model 테스트

[백엔드/Django] - [Django] Document 따라 읽기(5) - 앱 작성(2) [Django] Document 따라 읽기(5) - 앱 작성(2) [전체 보기] - [Django] Document 따라 읽기(4) - 앱 작성(1) [Django] Document 따라 읽기(4) - 앱 작성(1) [백엔드/Dj

dog-foot-writen.tistory.com


 

두 번째 테스트

Django에서는 View 레벨에서 코드와 상호작용 하는 사용자 시뮬레이션 Test를 제공합니다.

get 등의 함수를 통해 어플리케이션을 제어할 수 있습니다.

python manage.py shell
from django.test.utils import setup_test_environment
setup_test_environment()

from django.test import Client
client = Client()


# 저희는 / 경로에 아무것도 지정하지 않았기 때문에 404로 return됩니다.
response = client.get("/")
response.status_code
# 404

# reverse 함수는 polls 에서 index를 찾아 url 을 반환합니다.
from django.urls import reverse
response = client.get(reverse("polls:index"))
response.status_code
# 200

 

 

 

View 개선

현재 polls 애플리케이션에서는 pub_date가 오지 않은 여론조사 또한 출력됩니다. 하지만 pub_date가 미래의 날짜라면 화면에는 나오지 말아야 하기 때문에 해당 부분을 수정하도록 하겠습니다.

# polls/views.py

from django.utils import timezone

class IndexView(generic.ListView):
    
    ...생략...
    
    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_dat")[:5]

Question.objects.filter(pub_date__lte= timezone.now()) 는 timezone.now() 보다 이전 값을 반환합니다.

filter 메서드의 많은 사용 방법은 공식 Document로 대체 하겠습니다.

 

 

새로운 View 테스트

이제 Question에 과거, 미래의 날짜가 포함된 질문을 만들고, pub_date로 제대로 항목들이 나열되는지 확인해야 합니다.

저희는 첫 번째 테스트와 같은 테스트 코드를 작성하겠습니다.

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

    # question이 없는지 체크합니다.
    # "No polls are available" 메세지와 latest_question_list가 비어있는지 체크합니다.
    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"], [])

    # create_question 함수를 통해 pub_date가 과거인 question을 생성합니다.
    # 이후 polls의 index 페이지로 넘어간뒤 latest_question_list에 question이 존재하는지 체크합니다.
    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],
        )
        
    # create_question 함수를 통해 pub_date가 미래인 question을 생성합니다.
    # 이후 polls의 index 페이지로 넘어간뒤 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"], [])

    # test_past_question(), test_future_question()을 합친 테스트 코드입니다.
    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],
        )
	
    # 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],
        )

 

 

DetailView 테스트

만약 질문이 index페이지에 표시되지 않더라도 올바른 URL을 알고있거나 추측하여 들어온다면 해당 질문에 접근할 수 있게됩니다. 따라서 다음과 같은 제약 조건을 추가하겠습니다.

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

 

이후 Question의 pub_date가 과거인 값이 표시되어지는지, 미래인 값이 표시되어지는지에 대한 테스트 코드를 작성합니다.

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