[TDD] Test-Driven Development with Python 7장

SUNGJIN KIM·2022년 7월 30일
0

tdd-with-python

목록 보기
7/7
post-thumbnail

˗ˋˏ♡ˎˊ˗ 멋있게 만들기 : 레이아웃, 스타일링, 테스트

  • 레이아웃과 스타일을 기능적으로 테스트 하기
  • 멋있게 만들기 : CSS 프레임워크 이용
  • Django 템플릿 상속
  • 부트스트랩 통합하기
  • Django의 정적 파일
  • 부트스트랩 컴포넌트를 이용한 사이트 외형 개선
  • collectistatic 과 다른 정적 디렉토리

레이아웃과 스타일을 기능적으로 테스트 하기

스모크 테스트 (Smoke Test)를 이용해서 CSS가 로딩되었는지 확인한다.

functional_test/tests.py

    def test_layout_and_styling(self):
        # 에디스는 메인 페이지를 방문한다.
        self.browser.get(self.live_server_url)
        self.browser.set_window_size(1024,768)

        # 그녀는 입력 상자가 가운데 배치된 것을 본다
        inputbox = self.browser.find_element(By.ID,'id_new_item')
        self.assertAlmostEqual(
            inputbox.location['x'] + inputbox.size['width'] / 2,
            512,
            delta=10
        )

기능 테스트 실행 시 아래와 같이 오류가 발생한다.

   self.assertAlmostEqual(
AssertionError: 104.0 != 512 within 10 delta (408.0 difference)

스타일링을 적용하기 위한 적절한 솔루션을 찾기 위해 다시 원상 복귀한다.

    <h1>작업 목록 시작</h1>
    <form method="POST" action="/lists/new">
        <!-- <p style="text-align : center;"> -->
        <input name="item_text" id="id_new_item" placeholder="작업 아이템 입력" />
        <!-- </p> -->
        {% csrf_token %}
    </form>

멋있게 만들기 : CSS 프레임워크 이용

부트스트랩(BootStrap) 을 이용해보도록 한다.
https://getbootstrap.com/

다운로드를 마친 후, list 앱 내 "static" 폴더를 만들어서 저장하도록 한다.

Django 템플릿 상속

공통 템플릿인 'superclass' 를 만들어서 두 개 템플릿이 이것을 상속하도록 한다.

python $ cp lists/templates/home.html lists/templates/base.html

base.html 이라는 공통 템플릿을 만들어서 상용구 코드를 추가하고 자식 템플릿이 커스터마이징 할 수 있는 blocks 을 설정하도록 한다.

<html>

<head>
    <title>To-Do lists</title>
</head>

<body>
    <h1>{% block header_text %}{% endblock %}</h1>
    <form method="POST" action="{% block form_action %}{% endblock %}">
        <!-- <p style="text-align : center;"> -->
        <input name="item_text" id="id_new_item" placeholder="작업 아이템 입력" />
        <!-- </p> -->
        {% csrf_token %}
    </form>
    {% block table %}
    {% endblock %}
</body>

</html>

base 템플릿에는 blocks 라는 연속 영역을 정의하는데,
자식 템플릿의 콘텐츠를 추가하거나 연동할 수 있는 영역이다.
lists/templates/home.html

{% extends 'base.html' %}
<html>

<head>
    <title>To-Do lists</title>
</head>

<body>
    <h1>{% block header_text %}작업 목록 시작{% endblock %}</h1>
    <form method="POST" action="{% block form_action %}lists/new{% endblock %}">
        <input name="item_text" id="id_new_item" placeholder="작업 아이템 입력" />
        {% csrf_token %}
    </form> 
    <table id="id_list_table">
        {% for item in items %}
        <tr>
            <td>{{ forloop.counter }}: {{item.text}}</td>
        </tr>
        {% endfor %}
    </table>
</body>

</html>

lists/templates/list.html

{% extends 'base.html' %}
<html>

<head>
    <title>To-Do lists</title>
</head>

<body>
    <h1>{% block heaer_text %}작업 목록 시작{% endblock %}</h1>
    <form method="POST" action="{% block form_action %}/lists/{{list.id}}/add_item{% endblock %}">
        <input name="item_text" id="id_new_item" placeholder="작업 아이템 입력" />
        {% csrf_token %}
    </form>
    {% block table %}
    <table id="id_list_table">
        {% for item in list.item_set.all %}
        <tr>
            <td>{{forloop.counter}}: {{item.text}}</td>
        </tr>
        {% endfor %}
    </table>
    {% endblock %}
</body>

</html>

FT 실행 시, 이전과 동일한 결과가 나오는 것을 확인하였다.
커밋 후 다음 스텝으로 넘어가본다.

부트스트랩 통합하기

CSS 적용해보도록 한다.

lists/templates/base.html

<!DOCTYPE html>
<html lang="en">

<head>
    <title>To-Do lists</title>
    <meta name="viewport" content="width=device-width, initial-scale = 1.0">
    <link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>

<body>
    <div class="container">
        <div class="row">
            <div class="col-md">
            <div class="text-center">
                <h1>{% block header_text %}{% endblock %}</h1>
                <form method="POST" action="{% block form_action %}/lists/new{% endblock %}">
                    <input name="item_text" id="id_new_item" placeholder="작업 아이템 입력" />
                    {% csrf_token %}
                </form>
            </div>
        </div>
    </div>
  </div>
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
                {% block table %}
                {% endblock %}
        </div>
    </div>
	</body>

</html>

CSS 가 동작하지 않는 것을 확인 할 수 있다.

Django의 정적 파일

웹 서버에서 정적 파일 (Static File)을 다루기 위해서 다음 두 가지 사항을 고려해야 한다.

  1. URL이 정적 파일을 위한 것인지 뷰 함수를 경유해서 제공되는 HTML을 위한 것인지 구분할 수 있는가?
  2. 사용자가 원할 때 어디서 정적 파일을 찾을 수 있는가?

정적 파일은 특정 URL을 디스크 상에 있는 파일과 매칭시키는 역할을 한다.
접두사는 /static/으로 초기 설정돼 있다. setting.py 을 통해 조정할 수 있다.

/static/이라는 URL 접두사를 사용하지 않았기 때문에, 동작하지 않았다.
base.html에 있는 CSS 파일 링크 부분을 아래와 같이 변경한다.

lists/templates/base.html

<head>
    <title>To-Do lists</title>
    <meta name="viewport" content="width=device-width, initial-scale = 1.0">
    <link href="/static/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>

수동으로 진입했을때, 변경되었음을 확인할 수 있다.
FT를 실행했을때, 그래도 실패하는 것을 확인할 수 있는데 이는 LiveServerTest는 자동으로 정적파일을 찾을 수 없기 때문이다.

이에 StaticLiveServerTestCase로 변경해줘야한다.

from django.contrib.staticfiles.testing import StaticLiveServerTestCase

class NewVisitorTest(StaticLiveServerTestCase):

부트스트랩 컴포넌트를 이용한 사이트 외형 개선

jumbotron 이라는 클래스를 이용하여 레이아웃을 변경해주도록 한다.
아래 코드는 모든 스텝을 다 한 이후의 코드이다.
base.html

<div class="container">
        <div class="row">
            <div class="col-md jumbotron">
                <div class="text-center">
                    <h1>{% block header_text %}{% endblock %}</h1>
                    <form method="post" action="{% block form_action %}{% endblock %}">
                        <input name="item_text" id="id_new_item" class = "form-control input-lg" placeholder="작업 아이템 입력" />
                        {% csrf_token %}
                    </form>
                </div>
            </div>
        </div>
    </div>

list.html

 <table id="id_list_table" class = "table">

사용자 지정 CSS 사용하기

사용자 지정 CSS를 설정하여 타이틀과 입력상자 사이에 간격을 만들어 준다.

base.html

<head>
    <title>To-Do lists</title>
    <meta name="viewport" content="width=device-width, initial-scale = 1.0">
    <link href="/static/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
    <link href="/static/base.css" rel="stylesheet" media="screen">
</head>

lists/static/base.css

#id_new_item {
    margin-top : 2ex;
}

collectistatic 과 다른 정적 디렉토리

개발 단계에서는 이렇게 사용해도 크게 문제가 되지 않지만, 실제 운영 중인 웹 서버에서 Django가 정적 콘텐츠를 제공하도록 하는 것은 매우 느리며 비효율적이다.

이에 여러 앱에 존재하는 모든 정적 파일을 한 곳에 모아서 배포용으로 만들어 둘 필요가 있다.

이 작업을 해주는 것이 collectistatic이다.
수집된 정적 파일이 모이는 위치는 settings.py 의 STATIC_ROOT 항목을 통해 설정한다.
실습 한번하고, 해당 항목 값을 리포지토리 밖에 있는 폴더로 지정한다.

settings.py

STATIC_URL = '/static/'
STATIC_ROOT = os.path.abspath(os.path.join(BASE_DIR,'lists/static'))

lists/static 폴더에 해당 내용을 생성하였다.
관리사이트는 Django가 가진 강력한 기능이나, 현재단계에서는 필요없으므로 꺼준 후 커밋한다.

이번 장에서 다루지 못한 것

  • LESS를 이용한 부트스트랩 커스터마이징
  • DRY와 손쉬운 URL 코딩을 위한 {% static %} 템플릿 태그
  • bower 같은 클라이언트 측 패키징 툴

마무리

이번에는 레이아웃 관련된 부분이여서 관련된 지식이 없는 나로써는
하나씩 부딪혀보며 고쳐보았단 것 같다.

특히 text-center 관련해서 조금 애먹었다.
도서에서 나오는 그대로 따라하긴했는데 실제로 적용했을 때는 가운데 정렬이 되지 않았었다.

참고 도서 : 클린 코드를 위한 테스트 주도 개발 (비제이퍼블릭,2015)

profile
#QA #woonmong

0개의 댓글