본문 바로가기

Posts/Python

파이썬을 이용한 클린 코드를 위한 TDD - 3장 단위 테스트 적용

반응형

Chapter 3. 단위테스트를 이용한 간단한 홈페이지 테스트 적용

TDD 학습 겸 정리를 위한 내용입니다.


1. 단위 테스트와 기능 테스트

1-1. 단위 테스트

프로그래머 관점에서 그 내부를 테스트하는 것

1-2. 기능 테스트

사용자 관점에서 애플리케이션 외부를 테스트 하는것

1-3. 테스트 작업 순서
  1. 기능 테스트를 작성해 사용자 관점에서 새 기능을 정의
  2. 기능 테스트를 실패하고 나면 테스트를 어떻게 통과해야할지 방법을 고민
    1. 이때 하나 이상의 단위 테스트를 적용하여 어떻게 코드가 동작해야 하는지 정의
  3. 단위 테스트가 실패하면 단위 테스트를 통과할 수 있을 정도의 최소한 코드 수정
    1. 이때 기능 테스트가 완전해질 때까지 과정 2와 3을 반복
  4. 기능 테스트를 실행하여 통과하는지 확인
    1. 통과하지 않을시 다시 단위 테스트 작성

위에 작업 순서를 보면 기능 테스트는 상위 레벨의 개발을 주도, 단위 테스트는 하위 레벨을 주도하는 의미로 파악할 수 있습니다.

이를 통해 알 수 있는 점은 기능 테스트는 기능성을 갖춘 애플리케이션 구축을 가능하도록 도와주며 단위 테스트는 깔끔하고 버그 없는 깨끗한 코드를 작성할 수 있게 도와줍니다.


2. Django의 단위 테스트

TDD 주기는 실패 테스트를 작성 후 테스트를 통과할 수 있는 코드를 작성하는 과정입니다. 단위 테스트의 경우는 자동화된 테스트 실행자에 의해 실행됩니다.

class SampleTest(TestCase):
    def test_bad_maths(self):
        self.assertEqual(1 + 1, 3)

명령은 $ python manage.py test 로 실행합니다.

image


3. 애플리케이션 코드 작성

보통 웹서비스에서 Django의 주요 역할은 사용자가 특정 url에 요청을 보내면 비지니스 로직을 처리하고 그에 따른 응답을 내려줍니다.

이때 장고가 동작하는 순서는 다음과 같습니다.

  1. 특정 URL에 http 요청을 받는다.
  2. 해당 요청이 어떤 views 함수를 실행할지 결정한다.
  3. views에서 요청을 처리 후 http 응답으로 반환한다.

이때 테스트는 사이트 url을 검증하고 서버의 views 함수에서 html을 반환하는지 기능 테스트를 해야합니다.

from django.test import TestCase

# Create your tests here.
from django.urls import resolve

from lists.views import home_page


class HomePageTest(TestCase):
    def test_root_url_resolves_to_home_page_view(self):
        found = resolve('/') # django 내부 함수 url 해석시 일치하는지 여부 결정
        self.assertEqual(found.func, home_page) # 실행한 함수와 home_page가 같은지 

이때 home_page import 에러가 발생하면서 동작하지 않게 됩니다.

url path에 views에 작성한 home_page를 작성하여 동작할 수 있도록 해줍니다.

def home_page():
    return None

이후 테스트 명령어를 실행해보면 아래와 같이 테스트가 실패하게 됩니다.

image

이번에는 프로젝트 url.py에서 path 설정을 해주지 않았기에 발생하였습니다. 다음과 같이 설정합니다.

from django.contrib import admin
from django.urls import path

from lists import views

urlpatterns = [
    path("", views.home_page, name="home"), # "/" 는 '' 빈 공란으로 처리 
    path('admin/', admin.site.urls),
]

이후 다시 $ python manage.py test 명령을 실행하면 테스트에 성공하는 것을 확인할 수 있습니다.

image

이렇게 첫 단위테스트가 성공하게 되었습니다.

중간에 views 함수에 관한 과정을 건너뛰긴 했지만 테스트는 최대한 작은 단위로 하는 것을 권장합니다.


뷰를 위한 테스트를 작성시 단순히 빈 함수를 작성하는 것이 아닌

HTML 형식의 실제 응답을 반환하는 함수를 작성해야합니다.

    def test_home_page_returns_correct_html(self):
        request = HttpRequest()
        response = home_page(request)
        self.assertTrue(response.content.startswith(b'<html>'))
        self.assertIn(b'<title>To-Do Lists</title>', response.content)
        self.assertTrue(response.content.endswith(b'</html>'))
  1. HttpRequest 객체를 생성해 사용자가 어떤 요청을 브라우저에 보내는지 확인
  2. home_page의 응답을 취하고 응답 내용이 특정 속성을 가진지 구분
  3. 응답내용의 구성이 html로 시작하고 title은 같은지 마지막은 /html로 종료되는지 확인

해당 홈페이지 리턴 테스트 함수는 TypeError: home_page() takes 0 positional arguments but 1 was given 에러를 발생시킵니다.

이때부터는 단위테스트, 주기에 대해 고려해야합니다.

  • 터미널에서 단위 테스트 실행 후 어떻게 실패하는지 확인
  • 편집기상 실패 테스트를 수정하기 위해 최소한의 코드 변경

위 두가지를 반복적으로 수행합니다. 코드의 품질을 높이려면 코드 변경을 최소화해야 합니다.

최소한의 단위의 코드가 테스트에 의해 검증이 되면 신뢰성이 올라가기 때문입니다.

def home_page():
    pass

def home_page(request): # 테스트 시도
        pass

def home_page(request): # 테스트 시도
        return HttpResponse('<html><title>To-Do Lists</title>')

def home_page(request): # 테스트 시도
        return HttpResponse('<html><title>To-Do Lists</title></html>')

알아두어야 할 Tip

기능 테스트 실행
  • $ python funcional_test.py
단위 테스트 실행
  • $ python manage.py test
단위 테스트-코드 주기
  1. 터미널에서 단위 테스트 실행
  2. 최소 코드 수정
  3. 반복

Reference



반응형