첫 번째 장고 앱 작성하기, part 5
자동화된 테스트 소개
자동화된 테스트란?
테스트는 코드 작동을 확인하는 루틴이다.
테스트는 다양한 수준에서 작동하며 일부 테스트는 작은 세부 사항에 적용될 수 있다.(특정 모델 메서드는 예상대로 값을 반환함)
또 다른 테스트는 소프트웨어의 전반적인 작동을 검사한다(사이트에서 사용자 입력 시퀀스가 원하는 결과를 생성)
이것은 앱 작성하기 파트 2에서 shell을 사용해서 메소드의 동작을 검사하거나 애플리케이션을 실행하고 어떻게 작동하는 지 확인하기 위해 데이터를 입력해서 테스트했던 것과 동일하다.
자동화된 테스트에서 다른 점은 테스트 작업이 시스템에서 수행된다는 것으로, 한 번 테스트 세트를 작성한 이후에는 앱을 변경할 때 수동 테스트를 수행하지 않아도 원래 의도대로 코드가 작동하는 지 확인할 수 있다.
테스트를 만들어야 하는 이유
대부분의 사람들은 python/django 를 배우는 것 만으로 충분하다고 느낄 수 있고, 또 다른 것을 배우고 써보는 것이 지나치거나 불필요해 보일 수 있으며, 현재 설문조사 어플리케이션 제작한 것은 잘 돌아가고 있는 상태입니다.
현재 설문조사 어플리케이션 만드는 것이 django 프로그래밍의 최종 단계라면, 자동화 된 테스트를 어떻게 만드는 지는 알 필요가 없는데, 아직 더 많은 것을 하려고 한다면 자동화 테스트 작성을 배우는 것이 현명할 것 입니다.
테스트를 통해 시간을 절약 할 수 있다.
특정 시점까지는 제대로 작동하는지 확인 하는 것이 테스트로서 충분할 것이며, 더 정교한 어플리케이션에서는 구성 요소간에 수십 개의 복잡한 상호 작용이 있을 수 있다.
그러한 컴포넌트들 중 어느 하나에 대한 변경이 어플리케이션의 동작에 예기치 않은 결과를 초래할 수 있다.
여전히 작동하는 것처럼 보인다는 것은 당신이 무언가를 망가뜨리지 않았는지 확인하기 위해 당신의 코드 기능을 20가지의 다른 시험 데이터 변형과 함께 실행한다는 것을 의미할 수 있다.
이 수동 테스트 작업을 자동화된 테스트가 몇 초만에 해결한다면 많은 시간 단축이 있을 것이고, 무언가가 잘못 되어도 테스트를 통해 예기치 않은 동작을 일으키는 코드를 식별하는 데 도움이 될 것이다.
때로는 코드가 제대로 작동하고 있음을 알 때 테스트를 작성하는 것은 허드렛일로 보여서 너의 생산적이고 창의적인 프로그래밍 작업에서 떠나 매력적이지도 흥분되지도 않은 테스트 작성이라는 일을 하는 게 어려울 수 있다.
테스트 작성하는 자엄은 어플리케이션을 수동으로 테스트하거나 새로 발견된 문제의 원인을 확인하는 데 많은 시간을 투자하는 것보다 훨씬 더 효과적인 것이다.
테스트는 문제를 그저 식별하는 것이 아니라 예방한다.
테스트를 그저 개발의 부정적 측면으로 생각하는 것은 실수이다.
테스트가 없으면 어플리케이션의 목적 또는 의도 된 동작이 다소 불투명 할 수 있다. 심지어 자신의 코드 일 때도, 정확히 무엇을 하고 있는지 알아 내려고 노력하게 된다.
테스트는 이 불투명함을 바꾼다. 그 내부에서 코드를 밝혀 내고, 어떤 것이 잘못 될 때, 그것이 잘못 되었다는 것을 깨닫지 못했다고 할지라도, 잘못된 부분에 빛을 집중시킨다.
테스트코드를 더 매력적으로 만들자.
너가 훌룡한 소프트웨어를 만들었을 지 모르지만, 다른 많은 개발자들이 테스트가 부족하기 때문에 그것을 사용하려 하지 않을 것이다. 테스트가 없으면, 그들은 그것을 신뢰하지 않을 것이며, django의 최초 개발자 중 한 명인 jacob kaplan-moss는 테스트 없는 코드는 설계상 망가져 있는 것 이라고 말하기도 하였다.
테스트 작성을 시작해야하는 또 다른 이유는 다른 개발자들이 당신의 소트프웨어를 사용하는 것을 진지하게 고려하기 전에 테스트 코드를 보기 원하기 때문이다.
테스트는 팀이 함께 일하는 것을 돕는다.
이전의 내용은 어플리케이션을 유지 관리하는 단일 개발자의 관점에서 작성되었다. 복잡한 어플리케이션은 팀별로 유지 관리 되는데, 테스트는 동료가 실수로 코드를 손상시키지 않는다는 것을 보증한다.
장고 프로그래머로서 생계를 꾸려 나가려면 테스트를 잘 해야하 한다.
기초 테스팅 전략
테스트 작성에 대한 많은 접근법이 있는데.
일부 프로그래머들은 테스트 기반 개발 이라는 학문을 따르고, 실제로 코드를 작성하기 전에 테스트를 작성한다. 직관에 반하는 것처럼 보일 수 있지만, 사실 대부분의 사람들이 종종 하는 일과 비슷하다. 문제를 설명한 다음 이를 해결하기 위해 코드를 생성하고, 테스트 기반 개발은 파이썬 테스트 케이스에서 문제를 공식화 한다.
더 흔하게는, 테스팅 입문자들은 코드를 작성하고 시간이 흐른 뒤에 테스트들이 필요하다고 한단한다. 아마도 몇몇의 테스트는 더 빨리 작성하는 것이 좋을 것이다. 하지만 너무 늦게 시작해서는 안된다.
어디서부터 테스트를 작성해야 할 지 종잡을 수 없을 때가 많기 때문이다. 당신이 수천 줄의 파이썬 코드를 작성해 놓았다면 테스트 할 것을 고르는 것이 쉽지 않을 지도 모른다. 그럴때는 다음 새로운 기능을 넣거나 버그를 수정하는 등, 코드를 변령할 일이 있을 때, 첫 테스트를 작성하는 것이 유익할 것이다.
첫 번째 테스트 작성하기
버그 식별하기
다행이 polls 어플리케이션에는 우리가 즉시 해결할 수 있는 약간의 버그가 있다.
Question.was_published_recently() 메소드는 Question이 어제 게시된 경우 True를 반환할 뿐 아니라 Question이 pub_date필드가 미래로 설정되어 있을 때도 그렇다
shell을 사용해 미래의 날짜로 메소드를 실행해 버그를 확인해보자
$ python manage.py shell
>>> import datetime
>>> from django.utils import timezone
>>> from polls.models import Question
>>> # create a Question instance with pub_date 30 days in the future
>>> future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
>>> # was it published recently?
>>> future_question.was_published_recently()
True
미래는 최근(recent)가 아니기 때문에 이는 분명 잘못 된 것이다.
버그를 노출하는 테스트 만들기
문제를 테스트하기 위해 shell에서 방금 수행한 작업은 자동화 된 테스트에서 수행할 수 있는 작업이므로 자동화된 테스트로 바꿔야한다.
어플리케이션 테스트는 일반적으로 어플리케이션의 test.py 파일에 있으며, 테스트 시스템은 test로 시작하는 파일에서 테스트를 자동으로 찾는다.
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)
우리는 미래의 pub_date를 가진 Question 인스턴스를 생성하는 메소드를 가진
django.test.TestCase 하위 클래스를 생성했다. 그런 다음 was_published_recently()이 출력이 False가 되는지 확인했다.
테스트 실행
터미널에서 테스트를 실행한다.
$ python manage.py test polls
그러면 다음과 같이 볼 수 있습니다.
Creating test database for alias '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 "/path/to/djangotutorial/polls/tests.py", line 16, in test_was_published_recently_with_future_question
self.assertIs(future_question.was_published_recently(), False)
AssertionError: True is not False
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (failures=1)
Destroying test database for alias 'default'...
위 코드를 살펴보면 다음과 같습니다.
- manage.py test polls는 polls 어플리케이션에서 테스트를 찾습니다.
- django.test.TestCase 클래스의 서브 클래스를 찾았습니다.
- 테스트 목적으로 특별한 데이터베이스를 만들었습니다.
- 테스트 메소드 - 이름이 test로 시작하는 것들을 찾습니다.
- test_was_published_recently_with_future_question에서 pub_date필드가 30일 미래인 Question 인스턴스를 생성했습니다
- … assertIs() 메소드를 사용하여, 우리가 False가 반환되기를 원함에도 불구하고 was_published_recently() 가 True를 반환한다는 것을 발견했습니다.
테스트는 어떤 테스트가 실패했는지와 실패가 발생한 행 까지도 알려주는 것입니다.
버그 수정
우리는 이미 문제가 무엇인지 알고 있습니다.
Question.was_published_recently()는 pub_date가 미래에 있다면 False를 반환해야 한다.
models.py 에서 날짜가 과거에 있을 때에만 True 를 반환하도록 메소드를 수정해야한다.
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
그리고 테스트를 다시 진행하면 다음과 같다.
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Destroying test database for alias 'default'...
버그를 확인한 후 우리는 버그를 드러내는 테스트를 작성 하였으며 코드에서 버그를 수정하고 테스트를 통과했습니다.
다른 많은 것들이 미래에 우리의 어플리케이션에 해를 끼칠 수 있지만, 테스트를 실행하면 즉시 우리에게 경고를 줄 것이기에 부주의하게 동일한 버그를 쓰는 일은 없을 것입니다.
보다 포괄적인 테스트
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)
Question.was_published_recently()가 과거, 최근, 매래의 질문에 대해 올바른 값을 반환한다는 걸 확인시키기 위해 세가지 테스트를 가졌습니다.
다시 말해, polls 는 조그만 어플리케이션이지만, 미래에 그것이 얼마나 복잡해지든 그리고 그것이 다른 코드와 상호 작용하든 간에 테스트를 한 메서드가 예상대로 동작할 것 이라는 것을 어느 정도 보장하고 있다.
뷰 테스트
설문조사 어플리케이션은 상당히 대충대충 만들어져 있다. 이 어플리케이션은 pub_date필드가 미래에 있는 질문 까지도 포함하여 게시해야한다.
미래로 pub_date를 설정하는 것은 그 시기가 되면 질문이 게시되지만 그떄까지는 보이지 않는 것을 의미해야 하는 것이다.
뷰에 대한 테스트
위 버그를 고칠 때 우리는 먼저 테스트를 작성한 후 코드를 수정했다. 사실 그것은 테스트 주도의 개발의 한 예였지만, 어떤 순서로 일을 하느냐가 중요한 것이 아니다.
첫 번째 테스트에서 코드의 내부 동작에 대해 자세히 설명했는데, 이 테스트에서 웹 브라우저를 통해 사용자가 경험하는대로 동작을 확인하려고 함.
버그 수정 전 우리가 사용할 수 있는 도구를 살펴 보겠다.
장고 테스트 클라이언트
django는 뷰 레벨에서 코드와 상호 작용하는 사용자를 시뮬레이트하기 위해 테스트 클라이언트 클래스 Client 를 제공한다. 이 테스트 클라이언트를 tests.py 또는 shell 에서 사용할 수 있다.
또다시 shell 에서 시작할 것인데, tests.py 에서 필요하지 않았던 두 가지 일을 해야한다. 첫번째는 shell 에서 테스트 환경을 구성하는 것이다.
$ python manage.py shell
>>> from django.test.utils import setup_test_environment
>>> setup_test_environment()
response.context 와 같은 추가적인 속성을 사용할 수 있게 하기위해서 setup_test_environment()를 사용하여 템플릿 renderer 를 설치합니다.
이 메서드는 테스트 데이터베이스를 설정하지 않으므로 기존 데이터베이스에 대해 다음이 실행되며 이미 작성한 질문에 따라 출력이 약간 달라질 수 있습니다.
settings.py``의 ``TIME_ZONE 이 올바르지 않으면 예상치 못한 결과가 나올 수 있습니다. 초기에 설정했는지 기억이 나지 않으면 계속하기 전에 확인하십시오.
다음으로 우리는 테스트 클라이언트 클래스를 가져와야합니다. (나중에 ``tests.py``에서 우리는 자체 클라이언트와 함께 제공되는 django.test.TestCase 클래스를 사용할 것이므로 이것은 필요하지 않을 것입니다.
>>> from django.test import Client
>>> # create an instance of the client for our use
>>> client = Client()
준비가 되면, 우리는 고객에게 우리를 위해 작업을 요청할 수 있습니다.
>>> # get a response from '/'
>>> response = client.get("/")
Not Found: /
>>> # we should expect a 404 from that address; if you instead see an
>>> # "Invalid HTTP_HOST header" error and a 400 response, you probably
>>> # omitted the setup_test_environment() call described earlier.
>>> response.status_code
404
>>> # on the other hand we should expect to find something at '/polls/'
>>> # we'll use 'reverse()' rather than a hardcoded URL
>>> from django.urls import reverse
>>> response = client.get(reverse("polls:index"))
>>> response.status_code
200
>>> response.content
b'\n <ul>\n \n <li><a href="/polls/1/">What's up?</a></li>\n \n </ul>\n\n'
>>> response.context["latest_question_list"]
<QuerySet [<Question: What's up?>]>
뷰를 개선시키기
설문 조사 목록에는 아직 게시되지 않은 설문 조사 (즉, 장래에 pub_date가 있는 설문 조사)가 표시됩니다. 그것을 수정합시다.
튜토리얼 4장에서 ListView 클래스 기반 뷰를 소개했습니다.
class IndexView(generic.ListView):
template_name = "polls/index.html"
context_object_name = "latest_question_list"
def get_queryset(self):
"""Return the last five published questions."""
return Question.objects.order_by("-pub_date")[:5]
우리는 get_queryset() 메소드를 수정하여 timezone.now()와 비교하여 날짜를 검사하도록 변경해야 합니다. 먼저 가져 오기를 추가해야 합니다.
from django.utils import timezone
그리고 다음과 같이 get_queryset 메소드를 수정해야합니다:
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
]
Question.objects.filter(pub_date__lte=timezone.now())는 pub_date가 - 이하인,
즉 - 시간대.now ().를 포함하는 쿼리 세트를 반환함
새로운 뷰 테스트
이제 runserver를 실행하면 브라우저에 사이트가 적재되고 과거와 미래 날짜의 Questions이 생성되고, 퍼블리시된 것들만 리스트에 나타나는 것을 확인으로써 예상대로 동작하는 것에 만족할 수 있을 것이다.
앞으로 어떤 변화를 일으키더라도 이러한 점에 영향을 끼치지 않도록 하고 싶을 것이기에 위 shell에 기초를 둔 테스트를 작성해야한다.
polls/test.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],
)
일부를 더 자세히 살펴보면
먼저, 질문 생성 함수인 create_question은 테스트 과정 중 설문을 생성하는 부분에서 반복 사용함.
_test_no_questions 은 질문을 생성하지 않지만 No polls are available 메시지를 확인하고 _latest_question_list 가 비어있는지 확인함.
django.test.TestCase 클래스는 몇가지 추가적인 선언 메소드를 제공하니 유의해야함.
이 예제에서 우리는 :meth:`~django.test.SimpleTestCase.assertContains() 와
:meth:`~django.test.TransactionTestCase.assertQuerySetEqual()`을 사용한다.
test_past_question에서 우리는 질문을 생성하고 그 질문이 리스트에 나타나는지 확인함
test_future_question 에서 우리는 미래의 pub_date 로 질문을 만듭니다. 데이터 베이스는 각 테스트 메소드마다 재설정되므로 첫 번째 질문은 더 이상 존재하지 않으므로 다시 인덱스에 질문이 없어야함.
요컨데, 사이트에서 관리자 입력 및 사용자 경험에 대한 이야기를 하는 테스트를 만들었고, 모든 상태와 시스템 상태의 모든 새로운 변경 사항에 대해 예상하는 결과가 출력되는지 확인합니다.
test_past_question 에서 우리는 질문을 생성하고 그 질문이 리스트에 나타나는지 확인해야함.
Detailview 테스트하기
여기까지 따라오면 우리가 만드는 것이 잘 잘동할 것이다. 그러나 미래의 설문들은 목록에 나타나지는 않지만, 사용자가 URL 을 알고 있거나, 추측하면 접근할 수 있다.
그래서 우리는 DetailView 에 비슷한 제약 조건을 추가할 필요가 있다.
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())
그 후 _pub_date 가 과거이고 미래에 pub_date가 있는 _Question 이 표시되지 않는지 확인하기 위해 몇 가지 테스트를 추가해야함.
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)
더 많은 테스트를 위한 아이디어
우리는 비슷한 get_queryset 메소드를 Resultsview 에 추가하고 그 뷰에 대한 새로운 테스트 클래스를 생성해야한다,.
그것은 우리가 방금 만든 것과 매우 유사하며, 사실 계속 반복 작업을 할 것이다.
테스트를 추가하면서 다른 방법으로 애플리케이션을 개선 할 수도 있다. 예를 들어 선택 사항이 없는 사이트에 설문을 게시할 수 있다는 것은 바보같은 일이다.
그래서 우리의 뷰는 이를 확인하고 그러한 질문을 배제 할 것이다. 우리의 테스트는 선택사항이 없는 설문을 생성한 다음, 실제로 게시되지 않는지 테스트하고, 선택사항이 있는 설문을 작성하고 게시 여부를 테스트한다.
아마도 일반 사용자가 아닌 로그인 한 관리자는 게시되지 않은 설문을 볼 수 있어야함
다시 말하면, 소프트웨어를 추가하기 위해 필요한 것은 무엇이든 테스트를 수반해야함. 먼저 테스트를 작성한 다음 코드가 테스트를 통과하게 만들 것인지, 아니면 먼저 코드에서 로직을 처리 한 다음 이를 증명할 테스트를 작성해야함
어느 순간엔가 너무 많은 테스트 코드들을 보고 관리하기 힘들도록 너무 비대해 지는 것은 아닌가 생각할 수 있다.
테스트 할 때는, 많이 할 수록 좋다.
우리의 테스트가 통제 불능으로 성장하고있는 것처럼 보일 수 있다.
이 속도라면 곧 우리의 어플리케이션에서 보다 우리의 테스트의 코드가 더 많아질 것이고, 나머지 코드의 우아한 간결함과 비교했을 때, 반복하는 것은 미학적이다.
사실 비대해지는것은 중요하지 않으며, 테스트 코드들이 늘어나게 해야한다.
대부분의 경우 테스트를 한 번 작성한 다음 신경을 끄게 되는데. 이 테스트 코드의 유용한 기능들은 프로그램을 개발하는 동안 계속 해서 작동하고 있을 것이다.
이에 때로는 테스트를 업데이트해야한다.
우리가 선택지를 가진 설문들만 출력되도록 뷰를 수정한다고 가정 해 보면, 이 경우 기존 테스트 중 상당수가 실패 할 것이다. 테스트 결과를 최신으로 유지하기 위해 어떤 테스트를 수정해야하는지 정확하게 알려주므로 테스트가 스스로를 돌보는 데 도움이 되며,
최악의 경우 개발을 계속할 때 중복되는 테스트가 있을 수 있다. 그것은 문제가 아니며, 테스팅에서 반복하는 것은 좋은 일입니다.
테스트들이 현명하게 배열되어있는 한 관리가 어려워지지 않을 것이다. 경험에 근거한 좋은 방법 중에는 다음과 같은 내용이 있다.
각 모델이나 뷰에 대한 별도의 TestClass
테스트하려는 각 조건 집합에 대해 분리된 테스트 방법
기능를 설명하는 테스트 메소드 이름
추가 테스팅
이 튜토리얼에서는 테스트의 기본 사항에 대해서만 소개 했는데 여러분은 더 많은 것을 할 수도 있고, 또 사용할 수 있는 똑똑한 도구들이 많이 있다.
예를 들어, 이 전에 수행 한 테스트에서는 모델의 내부 로직과 뷰에서 정보를 게시하는 방법을 다루었지만 Selenium 같은 “브라우저 내” 프레임 워크를 사용하여 HTML이 브라우저에서 실제로 렌더링되는 방식을 테스트 할 수 있다.
이러한 도구를 사용하면 장고 코드의 동작뿐만 아니라 JavaScript도 확인할 수 있다. 테스트가 브라우저를 시작하고 인간이 그것을 다루는 것처럼 사이트와 상호 작용 것은 매우 중요하다!
Django에는 LiveServerTestCase가 포함되어있어 Selenium과 같은 도구와 쉽게 통합할 수 있게 해준다.
복잡한 어플리케이션을 사용하는 경우 연속적으로 통합하기 위해 모든 커밋마다 자동으로 테스트를 실행하여 품질 제어가 적어도 부분적으로 자동화되도록 할 수 있다.
어플리케이션에서 테스트되지 않은 부분을 탐지하는 좋은 방법은 코드 커버리지를 확인하는 것이다. 이것은 또한 깨지기 쉬운 코드나 심지어는 죽은 코드를 식별하는 데 도움이된다. 코드를 테스트 할 수 없다는 것은 대개 코드가 리팩터링해야하거나 제거해야 함을 의미한다. 커버리지는 죽은 코드를 확인하는 데 도움이 되며. 자세한 내용은 Integration with coverage.py 를참조해야 한다.
https://docs.djangoproject.com/ko/5.1/topics/testing/advanced/#topics-testing-code-coverage
장고 테스트는 테스트에 대한 포괄적인 정보를 제공한다.
테스트에 대한 자세한 내용은
https://docs.djangoproject.com/ko/5.1/topics/testing/
다음 장에서는
django 뷰를 테스트하는 것이 익숙해졌으면, 정적 파일 관리에 대해 배울 수 있는 다음 장을 보면된다.
'PYTHON-BACK' 카테고리의 다른 글
Django_tutorial_var4 (1) | 2025.01.22 |
---|---|
Django_tutorial_var3 (0) | 2025.01.21 |
Django_tutorial_var2 (1) | 2025.01.20 |
Django_tutorial_var1 (0) | 2025.01.20 |
# 24.11.28_영화추천 사이트 제작_협업 기반 필터링 (0) | 2024.11.28 |