관리 메뉴

Storage Gonie

34. (app2) Django 버그 수정 및 테스트 자동화하기(tests.py이용) 본문

웹개발/Django 웹서비스 개발(인프런)

34. (app2) Django 버그 수정 및 테스트 자동화하기(tests.py이용)

Storage Gonie 2019. 2. 20. 02:23
반응형

주제 : Model Question의 was_published_recently메소드를 자동으로 테스트하는 코드 작성하기.(테스트를 자동화하는 코드 작성)


# TDD(Test-driven development)

- 테스트를 먼저 작성하는 개발 방법론.

- 개발자는 먼저 요구사항(제약조건)을 검증하는 자동화된 테스트 케이스를 작성한다. 

- 그 다음 그 테스트 케이스를 통과하기 위한 최소한의 코드를 생성한다. 마지막으로 작성한 코드를 표준에 맞게 리팩토링한다.


Question의 was_published_recently메소드에는 작은 버그가 하나 있다. 

published_recently로 인식시키고 싶은 것은 ((하루전~현재)) 까지만 인데 ((현재~미래))도 published_recently로 인식된다는 것이다. 

이런 버그를 인식하게 돕는 테스트를 자동화 해주는 코드를 작성할 수 있다.


"python manage.py shell"

"import datetime"

"from django.utils import timezone"

"from polls.models import Question"

"fq = Question(pub_date = timezone.now() + datetime.timedelta(days = 2)) "

"fq.was_published_recently()"

-> True # ((현재~미래))의 날짜에 대해 원래 나왔으면 하는 결과는 False인데 True가 나온것이다.


1. tests.py에 TestCase를 상속받는 클래스 생성 후 메소드 추가

import  datetime
from django.utils import timezone

class SomeTest(TestCase):
def abc(self): # 테스트 실행시 자동으로 호출되지 않음.
print("abc")

2. 자동화된 테스트 실행

- "python manage.py test polls"

- Ran이 0개라고 뜨면서 아무것도 실행되지 않음.

3. 메소드의 이름을 test로 시작하도록 수정.

- 테스트 메소드는 반드시 'test'로 이름이 시작되어야 함

import  datetime
from django.utils import timezone

class SomeTest(TestCase):
def test_abc(self): # 테스트를 실행했을 때 자동으로 실행되게 하기 위해서는 이름이 'test'로 시작해야한다.
print("test abc")

4. 자동화된 테스트 재실행

- "python manage.py test polls"

- Ran이 1개라고 뜨면서 테스트 1개가 실행된 상태.

- test_abc()메소드는 정상적으로 호출되었는데 실제적으로 True, False와 같이 테스트 된건 없음

5. 테스트 되는 조건 추가

- self.assert~가 테스트의 핵심 메소드 들이다.

- 여러가지가 있는데 여기서는 self.assertIs(테스트 하고픈 조건, 기대하는 Boolean값)를 사용하여 테스트를 진행한다.

- 5 > 3은 원래 True인데 기대값에 False를 고의로 적어놨더니 FAILED가 뜬 것을 볼 수 있다.

- 이를 이용해서 was_published_recently를 테스트하는 메소드를 작성해보자.

class SomeTest(TestCase):
def test_abc(self): # 테스트를 실행했을 때 자동으로 실행되게 하기 위해서는 이름이 'test'로 시작해야한다.
print("test abc")
self.assertIs(5 > 3, False) # (테스트 하고픈 조건, 기대하는 Boolean 값)

6. 위의 클래스를 지워버리고 다음의 클래스 및 메소드로 교체해서 이제 본 작업에 진입.

- "python manage.py test polls"

- 테스트 코드에서 우리가 기대하는 것을 작성해 두었는데 이를 실행한 결과가 FAILED 했다.

- 이는 테스트한 부분에 버그가 있고, 수정해야함을 의미한다.

class QuestionMethodsTests(TestCase):
def test_was_published_recently_with_future_question(self):
time = timezone.now() + datetime.timedelta(days=7) # 현재 + 7일 즉, 미래의 날짜.
future_question = Question(pub_date = time)
self.assertIs(future_question.was_published_recently(), False)

7. 문제가 생긴 부분의 버그 수정

- models.py에서 Question의 was_published_recently()를 수정

def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1) # 어제 = (현재시간 - 하루)
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now

8. 다시 테스트 코드 실행 

- "python manage.py test polls"

- 성공적으로 테스트를 통과함.


9. 좀 더 다양한 테스트 추가

- "python manage.py test polls"

- 성공적으로 테스트들을 통과함.

class QuestionMethodsTests(TestCase):
# 7일 미래의 시간을 테스트하는 코드
def test_was_published_recently_with_future_question(self):
time = timezone.now() + datetime.timedelta(days=7) # 현재 + 7일 즉, 미래의 날짜.
future_question = Question(pub_date = time)
self.assertIs(future_question.was_published_recently(), False)

# 30일 전의 시간을 테스트 하는 코드
def test_was_published_recently_with_old_question(self):
""" was_published_recently() should return False for questions whose pub_date is older than 1 day. """
time = timezone.now() - datetime.timedelta(days=30)
old_question = Question(pub_date=time)
self.assertIs(old_question.was_published_recently(), False)

# 1시간 전의 시간을 테스트 하는 코드
def test_was_published_recently_with_recent_question(self):
""" was_published_recently() should return True for questions whose pub_date is within the last day. """
time = timezone.now() - datetime.timedelta(hours=1)
recent_question = Question(pub_date=time)
self.assertIs(recent_question.was_published_recently(), True)


** 귀찮지만 유닛테스트 같은것을 해주는게 좋은 습관이다.

반응형
Comments