-
Part 5 테스팅Django 2022. 7. 2. 17:20
테스트를 만들어야 하는 이유
- 테스트를 통해 시간을 절약 할 수 있습니다.
- 테스트는 문제를 그저 식별하는 것이 아니라 예방합니다.
- 테스트가 코드를 더 매력적으로 만듭니다.
- 테스트는 팀이 함께 일하는것을 돕습니다.
첫 번째 테스트 작성하기
polls/models.py에 기존에 작성한 코드를 살펴보면 약간의 문제가 있습니다.
생성날짜가 미래에 생성된 데이터는 최근으로 간주하지 않습니다.
미래의 날짜는 False로 나와야 합니다.shell을 사용해 미래의 날짜로 메소드를 실행해 버그를 확인해 봅시다.
관련 패키지들을 import하고
현재 시간에 30일을 더한 날의 생성날짜를 가진 Question을 만듭니다.
최근 식별 함수(was_published_recently( ))를 호출하면
미래생성 날짜임에도 불구하고 True가 나옵니다.방금 진행한 테스트를
shell에서 수동으로 작업하는 것이 아닌
명령어 하나로 확인할 수 있는 테스트코드를 작성하여자동화된 테스트로 만들어 보도록 하겠습니다.
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)테스트 작성시 파일 이름(test.py)과
함수이름(test_was_published_~~)의 앞부분은 test로 시작되어야 합니다.앞에 shell에서 입력한 내용과 동일합니다.
TestCase를 추가로 import 해 주었으며
결괏값이 False가 나오는지 테스트합니다.테스트 코드는 상황을 코드로 만들어주고
원하는 결괏값이 나오는지를 확인하는 것입니다.py manage.py test polls명령어를 입력하여 테스트를 실행해 봅시다.
예상했던대로 결괏값이 False가 아닌 True가 나오기 때문에
테스트를 실패한 것을 확인할 수 있습니다.테스트를 통과할 수 있도록
models.py에서 날짜가 과거에 있을 때에만 True를 반환하도록 다음과 같이 메소드를 수정한 후
다시 테스트를 실행하도록 하겠습니다.
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= nowQuestion 생성 날짜가 미래로 넘어가지 않도록
현재 날짜를 두고
최근 기준을 하루로 두었습니다.테스트가 통과된 것을 확인할 수 있습니다!
뷰 테스트
뷰 테스트는 사용자가 된 것처럼 요청(request)을 하고 response를 받아서
원하는 결괏값을 받는지 확인하는 것입니다.장고 테스트 클라이언트
shell을 실행해 주세요.(py manage.py shell)
현재 사용중인 데이터베이스를 이용해 테스트하기 위해
setup_test_environmen를 import하고 명령어를 입력해 주세요.다음으로 테스트 클라이언트 클래스를 import합니다.
이 client가 테스트 코드에서 사용자 역할을 합니다.클라이언트가 웹페이지를 호출하는 작업입니다.
상태 코드는 404로 출력되었습니다.
(서버에서 응답에 대한 상태를 코드로 전달해 줍니다.)테스트 클라이언트가 투표앱의 인덱스를 호출하게 되면 결괏값(response)을 받습니다.
response의 stauts_code, content, context 값을 전달받는 것을 확인할 수 있습니다.
뷰를 개선시키기
테스트 코드를 작성하기 전에 ListView를 다음과 같이 수정해주세요.
from django.utils import timezone
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_date')[:5]미래의 날짜가 나오지 않도록 filter를 넣어서 조건을 입력한 것입니다.
현재시간보다 작거나 같은(__lte) 데이터를 가져오도록 합니다새로운 뷰 테스트
polls/tests.py에 다음과 같이 뷰 테스트 코드를 추가합니다.
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):
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],
)url을 하드코딩하지 않도록 reverse를 import해 주었습니다.
테스트 데이터를 만들기 위해서 create_question( )함수를 만들었습니다.
함수를 호출하게 되면 데이터 하나가 만들어집니다.(데이터가 없는경우, 과거인 경우, 미래인 경우, ...)
데이터는 각 테스트 함수마다 재설정 되므로 필요할때마다 함수를 호출하여 만들어야 합니다.테스트를 실행하여 통과된 것을 확인할 수 있습니다.
출처 : django 웹 프로그래밍 강좌 (#5 test)(django test 사용, test case 작성, unit test)
'Django' 카테고리의 다른 글
Part 7 관리자 페이지 커스터마이징 (0) 2022.07.04 Part 6 정적 파일 (0) 2022.07.03 Part 4 폼과 기본 뷰 (0) 2022.07.02 Part 3 뷰와 템플릿 (0) 2022.07.01 Part 2-2 관리자 페이지 (0) 2022.06.29