Django - 테스트 케이스 (설문조사 3)

윤형·2024년 9월 11일

Django

목록 보기
5/12

테스트 코드

프로젝트를 진행하다 보면 내가 짠 코드가 잘 작동하는지만 확인하는 수준에 그치게 되는데, 이러한 개발은 좋은 개발이 아니다. 작동한다는 뜻이 버그가 없다는 뜻이 아니기 때문이다. 게다가 많은 개발자들과 협업하기 위해서는 테스트코드를 작성해놔야 서로 확인하기 수월하고 문제점을 예방할 수 있다. 그렇기 때문에!! 테스트 코드는 매우 중요하다고 할 수 있다...(사실 너무너무 귀찮음)



"polls/test.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)

-> 버그 발생!!

"polls/models.py"

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

코드를 추가해 버그를 방지 할 수 있다.


포괄적인 테스트 코드

def test_was_published_recently_with_old_question(self):
    """
    하루전 질문이 최신 질문인지 확인 - Flase면 테스트 통과
    """
    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):
    """
    23시간59분전 질문이 최신 질문인지 확인 - 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)

view 테스트

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

작동 설명

  1. reverse("polls:index") : Django의 리버싱 기능을 이용하여 polls앱의 index라는 이름이 붙은 URL패턴에 대한 URL경로를 반환한다.(urls.py에 있음)

  2. self.client.get("URL") : URL을 사용하여 HTTP GET요청을 보낸다. -> views.py에서 정보를 찾고, template_name의 경로에 맞는 템플릿을 호출하게 된다. 거기에 있는 정보들을 참조할수 있게 해준다. +) views.py에 있는 context_object_name은 템플릿에 사용될 변수 이름을 지정

  3. assert를 이용해 테스트 진행

정보) 코드가 200이면 성공

정보) 테스트 케이스에서는 각 메서드 실행시 데이터 베이스가 초기화 됨, 즉 독립적으로 실행되며 비어있는 가상 데이터 베이스로 테스트를 진행함

정보) 제너릭 뷰의 get_queryset() 메서드는 제너릭에서 제공되는 메서드임, 해당 뷰와 관련된 모든 객체를 반환, 객체를 필터링 가능

Django의 TestCase 클래스에서 사용할 수 있는 assert 메서드들을 알아보자

메서드기능
assertEqual(a,b)a 와 b가 같음을 비교한다. 같지 않으면 테스트 실패
assertNotEqual(a, b)a와 b가 다름을 확인합니다. 같으면 테스트 실패.
assertTrue(expr)expr가 True임을 확인. False이면 테스트 실패.
assertFalse(expr)expr가 False임을 확인. True이면 테스트 실패.
assertIsNone(expr)expr가 None임을 확인. None이 아니면 테스트 실패.
assertIsNotNone(expr)expr가 None이 아님을 확인. None이면 테스트 실패.
assertIn(item, container)item이 container에 포함되어 있음을 확인. 아니면 실패
assertNotIn(item, container)item이 container에 포함되어 있지 않음을 확인. 포함되어 있으면 테스트 실패.
assertContains(response, text)response의 내용에 text가 포함되어 있음을 확인합니다. 포함되어 있지 않으면 테스트 실패.
assertNotContains(response, text)response의 내용에 text가 포함되어 있지 않음을 확인합니다. 포함되어 있으면 테스트 실패.
assertQuerySetEqual(qs, expected)쿼리셋 qs와 expected가 동일한지 확인합니다. 다르면 테스트 실패.
assertRedirects(response, expected_url)response가 지정된 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)

python3 manage.py test polls

profile
제가 관심있고 공부하고 싶은걸 정리하는 저만의 노트입니다.

0개의 댓글