Question.was_publishd_recently() 메서드는, Question 이 어제 이전에 발행되었거나, Question 의 pub_date 필드가 미래일일 경우에 True 를 반환합니다.
쉘을 통해성 버그를 확인하고 확실하게 찾아냅시다. shell 을 사용해서 날짜가 미래의 날짜로 지정된 질문의 메서드를 확인 합니다.
1
python manage.py shell_plus
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
In [1]: import datetime
In [2]: from django.utils import timezone
In [3]: from polls.models import Question
In [4]: # pub_date 이 30일 미래 날짜를 가진 Question 인스턴스 생성
In [5]: future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
In [6]: # 이게 최근에 발행 됬나요?
In [7]: future_question.was_published_recently() Out[7]: True
In [8]: # 최근 발행된 질문이 아닌데도 True 가 표시됩니다. 버그 입니다.
발행일짜가 30일 이후로 되어 있는데도, 최근인지 확인하는 메서드는 True 를 반환합니다.
이것은 명백하게 잘못되어 있는것입니다.
버그를 노출시키는 테스트
방금 shell 에서 진행 한것은, 자동화 테스트가 문제점에 대해서 정확히 무엇을 할수 있는지 테스트 해본 겁니다.
자, 그럼 자동화 테스트로 전환을 해봅시다.
관례적으로 어플리케이션의 테스트는 어플리케이션의 tests.py 파일에 작성합니다. 테스트 시스템은 자동으로 테스트 코드들을 test 로 시작하는 파일에서 찾습니다.
polls/tests.py 파일을 생성하고
아래 코드를 작성해 줍니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
from django.test import TestCase import datetime from django.utils import timezone
from .models import Question
# Create your tests here
classQuestionModelTests(TestCase): deftest_was_published_recently_with_future_question(self): """ was_published_recently() 가 pub_date 가 미래 날짜로 지정되어 있는 질문들에 대해서 False 를 반환함 """ time = timezone.now() + datetime.timedelta(days=30) future_question = Question(pub_date=time) self.assertIs(future_question.was_published_recently(), False)
여기에 우리는 django.test.TestCase 서브 클래스를 만들고, pub_date 가 미래 날짜인 Question 인스턴스를 만들어 줍니다. 그 후에, 값이 False 여야 하는 was_published_recently() 의 결과를 체크합니다.
테스트 실행하기
터미널에서 테스트를 실행 할수 있습니다.
1
python manage.py test polls
실행해 보면, 아래와 같은 스크린을 볼수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Creating test database foralias'default'... System check identified no issues (0 silenced). F ====================================================================== FAIL: test_was_published_recently_with_future_question (polls.tests.QuestionModelTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/dhkang/django_tutorial/mysite/polls/tests.py", line 19, in test_was_published_recently_with_future_question self.assertIs(future_question.was_published_recently(), False) AssertionError: True is not False
---------------------------------------------------------------------- Ran 1 testin 0.001s
FAILED (failures=1) Destroying test database foralias'default'...
무엇이 발생했냐면..
manage.py test polls 명령어를 실행하여, polls 앱 안에 test 를 찾았습니다
django.test.TestCase 클래스의 서브 클래스를 찾았습니다
테스트의 목적을 수행할 특수한 데이터베이스를 하나 생성했습니다
test 로 시작하는 테스트의 메서드를 찾습니다
test_was_published_recently_with_future_question 안에 Question 인스턴스를 하나 생성합니다. 이때, pub_date 는 30일 이후의 날짜로 지정해서 생성합니다
assertIs() 함수를 사용해서, False 가 반환되어야 하는데, was_published_recently() 가 True 를 반환하는것을 발견합니다
테스트는 어떤 테스트가 실패했고, 어느 줄에서 실패가 발생했는지 알려줍니다.
버그 수정하기
우리는 이미 문제점이 무엇인지 알고 있습니다.
Question.was_published_recently() 는
pub_date 가 미래의 날짜일 경우,
False 를 반환 해야 합니다.
polls/models.py 의 이 메서드를 수정해 줍니다.
1 2 3
defwas_published_recently(self): now = timezone.now() return now - datetime.timedelta(days=1) <= self.pub_date <= now
수정을 마쳤으면, 테스트를 다시 실행 해 줍니다. python manage.py test polls
1 2 3 4 5 6 7 8 9
python manage.py test polls Creating test database foralias'default'... System check identified no issues (0 silenced). . ---------------------------------------------------------------------- Ran 1 testin 0.001s
OK Destroying test database foralias'default'...
버그를 확인한 뒤에, 버그를 노출 시키는 테스트를 작성 하였고.
버그를 코드에서 수정하여, 테스트를 통과하게 만들었습니다.
향후, 다른 많은 부분들이 우리의 어플리케이션에서 잘못될수 있습니다. 하지만, 우리는 이 버그를 다시 가지지 않을것입니다. 왜냐하면, 테스트를 실행 시키기만 하면, 바로 버그에 대한 경고를 받을 수 있기 때문입니다.
이 부분에 대해서 고쳐졌다고 볼수 있습니다.
좀더 다양한 테스트
was_published_recently() 를 조금 더 고쳐보기로 합니다. 사실 이것은 긍정적인 의미를 가진 당황스러움 이 있습니다.
polls/tests.py 파일을 열고, 두개의 테스트를 같은 클래스에 추가해 줍니다
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
deftest_was_published_recently_with_old_question(self): """ was_published_recently() returns False for question 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) deftest_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 = Quesiton(pub_date=time) self.assertIs(recent_question.was_published_recently(), True)
이제 Question.was_published_recently() 가 과거, 현재, 미래 날짜에 발행된 질문들에 대한 체크에 센스 있는 값을 반환 하는지 봅니다.
python manage.py test polls를 실행해 봅니다. 3개의 테스트를 진행 했고, OK 가 표시되는것을 확인 할수 있습니다.
1 2 3 4 5 6 7 8
Creating test database foralias'default'... System check identified no issues (0 silenced). ... ---------------------------------------------------------------------- Ran 3 tests in 0.002s
OK Destroying test database foralias'default'...
다시 한번, 튜토리얼에서 만든 polls 어플리케이션은 매우 최소한의 단위를 가진 어플리케이션 입니다.
하지만, 향후에는 더 복잡함이 자라날것이고, 다른 코드들과 상호 작용을 함에 있어서, 더 복잡해 질것입니다.