[백엔드/Django] - [Django] Document 따라 읽기(5) - 앱 작성(2)
테스트를 생성해야 하는 이유
시간 절약
지금까지 생성한 설문조사 애플리케이션은 매우 단순하지만 보다 정교하고 복잡한 애플리케이션에서는 구성 요소 간에 수십 개의 복잡한 상호 작용이 있을 수 있습니다. 이러한 구성 요소가 변경되면 응용 프로그램 동작에 예상치 못한 결과가 발생할 수 있어 여러 테스트 코드를 통해 기능에 문제가 발생하지 않았는지 확인할 수 있다.
문제 예방
테스트를 통해 의도된 동작들이 제대로 수행되는지 미리 테스트해 볼 수 있으며 이것은 자기 자신의 코드가 어떤 동작을 하는지 알기 위해 확인하는 과정이다.
팀 내 협력
단일 개발자가 아니라면 복잡한 애플리케이션에서 유지 관리하는 것은 어려운 일이지만 테스트를 통해 팀 내 동료 혹은 내가 코드를 손상시키지 않도록 보장해 준다.
TDD에 대해서는 이후 새로운 게시글로 심도 있게 작성하겠습니다.
첫 번째 테스트 작성하기
버그 식별
이전 글에서 생성한 polls에는 오류가 있습니다.
Question.was_published_recently() 메서드에서 마지막날 내에 Question이 게시되었지만 Question의 pub_date필드가 미래의 값이 입력되는 경우에도 True를 반환하게 됩니다.
python manage.py shell
import datetime
from django.utils import timezone
from polls.models import Question
future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
future_question.was_published_recently()
# True
polls의 Question에 구현된 was_published_recently는 1일 이내에 게시되었는지 확인하는 목적의 함수였지만 위 코드처럼 30일을 더해주어도 True를 반환하고 있습니다.
테스트 코드 작성
Django에서 테스트를 위한 기본 경로는 응용프로그램의 tests.py 파일에 있습니다. 따라서 shell을 통해 자동 테스트를 수행할 수 있도록 tests.py를 작성하겠습니다.
# 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() 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)
위의 shell에서 수행한 것과 동일하지만 self.assertIs를 통해 테스트를 구현하였습니다.
python manage.py test polls
수행되는 작업은 다음과 같습니다.
- manage.py에 test "애플리케이션명"을 통해 polls의 django.test.TestCase class를 찾습니다.
- 테스트를 위한 데이터베이스를 생성합니다.
- test로 시작하는 test method들을 찾습니다.
- test_was_published_recently_with_future_question에서 Question에 30일을 더한 값을 pub_date에 할당합니다.
- assertIs() 메서드가 was_published_recently()를 수행하고, True를 반환하지만 제가 지정한 False와 다르기 때문에 테스트를 실패합니다.
버그 수정
이미 어느 곳에서 에러가 발생하는지 알고 있기 때문에 해당 코드를 날짜가 과거인 경우에만 반환되도록 메서드를 수정하도록 하겠습니다.
# polls/models.py
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
다시 테스트를 진행한다면 테스트가 에러 없이 정상적으로 수행되는 것을 알 수 있습니다.
포괄적인 테스트
동일한 클래스에 대해 테스트 메서드를 여러 개 추가함으로써 해당 메서드를 더 포괄적으로 테스트할 수 있습니다.
was_published_recently()를 과거, 최근, 미래 질문에 대해 합리적인 값을 반환하는지 확인하도록 테스트 코드를 추가하겠습니다.
def test_was_published_recently_with_old_question(self):
"""
was_published_recently() returns False for questions whose pub_date
is older than 1 day.
"""
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() returns True for questions whose pub_date
is within the last day.
"""
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)
'백엔드 > Django' 카테고리의 다른 글
[Django] Document 따라 읽기(7) - View 테스트 (0) | 2023.11.14 |
---|---|
[Django] Document 따라 읽기(5) - 앱 작성(2) (0) | 2023.11.10 |
[Django] Document 따라 읽기(3) - admin 페이지 (0) | 2023.11.06 |
[Django] Document 따라 읽기(1) - Tutorial(설치, 데이터베이스 연결) (0) | 2023.11.04 |
[Django] Documnet 따라 읽기(2) - View, Model, CRUD API(1) (1) | 2023.11.03 |
[Django] Django(장고)란? (0) | 2023.10.27 |