Seul Lee

Mathpresso 서버 개발자

Navigation
 » Home
 » Github
 » XML Feed

TDD in python, 02

05 Apr 2017 » test, django

(파이썬을 이용한) 클린 코드를 위한 테스트 주도 개발 책 내용을 공부하면서 정리한 글

작업 환경

  • macOS Sierra, 10.12.3
  • python, 3.6.0
  • django, 1.9.7
  • selenium, 3.3.1
  • firefox, 52.0.1


2. 1부 TDD와 Django 개요에서 막힌 부분 정리

ch05, ch06에서 알 수 없는 에러로 인해 진행이 어려웠던 부분들을 정리


2.1 POST 요청을 전송하기 위한 폼(Form) 연동

Page 61

<form method="POST">
  <input id="id_new_item" name="item_text" placeholder="Enter a to-do item" />
  {\% csrf_token \%}
</form>

이 부분에서 기능 테스트 수행 시 table 안에서 입력한 값을 제대로 찾지 못하는 에러가 발생한다.

삽질 도중 발견한 Stackoverflow에서 본 해결 방법!

from django.test import LiveServerTestCase
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.expected_conditions import staleness_of
from selenium.webdriver.common.keys import Keys
from contextlib import contextmanager
import unittest


class NewVisitorTest(LiveServerTestCase):

    @contextmanager
    def wait_for_page_load(self, timeout=30):
        old_page = self.browser.find_element_by_tag_name('html')
        yield WebDriverWait(self.browser, timeout).until(
                            staleness_of(old_page)
                            )

        [....]

        # 엔터키를 치면 페이지가 갱신되고 작업 목록에
        # "1: 공작깃털 사기" 아이템이 추가된다
        inputbox.send_keys(Keys.ENTER)

        with self.wait_for_page_load(timeout=5):
            self.check_for_row_in_list_table('1: 공작깃털 사기')

       [....]

        # 페이지는 다시 갱신되고, 두 개 아이템이 목록에 보인다
        with self.wait_for_page_load(timeout=10):
            self.check_for_row_in_list_table('2: 공작깃털을 이용해서 그물 만들기')
            self.check_for_row_in_list_table('1: 공작깃털 사기')

입력 후 약간의 시간을 준 이후 확인하도록하여 오류를 없앤다.



2.2 test_home_page_can_save_a_POST_reqeust

Page 76

기능 테스트 중 POST 요청으로 보낸 아이템이 저장되어 실제로 html로 보여지는지 확인하는 부분에서

self.assertEqual(response.content.decode(), expected_html)에서 오류가 발생한다.


AssertionError: ‘<!DO[263 chars] <input type='hidden' name='csrfmiddlew[159 chars]tml>’ != ‘<!DO[263 chars]
n </form>\n\n <table id=”id_list_t[62 chars]tml>’


해당 에러는 csrf_token으로 인해 input의 value값이 달라지기때문에 발생한다.


class HomePageTest(TestCase):

    [....]

    def test_home_page_returns_correct_html(self):
        request = HttpRequest()
        response = home_page(request)
        expected_response = render(request, 'home.html')
        self.assertEqual(response.content.decode(),
                         expected_response.content.decode())

                        
    [....]

Page 82에 나오는 test_home_page_displays_all_list_items에도 적용할 수 있다.



2.3 Regex didn’t match: ‘/lists/.+’ not found in ‘http://localhost:8081/’

Page 99


self.assertRegex(edith_list_url, ‘/lists/.+’) AssertionError: Regex didn’t match: ‘/lists/.+’ not found in ‘http://localhost:8081/


와 같은 에러를 Ch6이 끝날 때까지 내뿜는다. 이 문제는 keys.ENTER를 실행할 때마다 새로운 리스트가 생성되고 그 리스트에 해당하는 URL로 이동한 이후에 edith_list_url, ‘/lists/.+’ 두 개를 비교해야하지만 이동이 되기 전에 assert문이 실행되기때문에 오류가 발생한다.

따라서 명시적으로 time.sleep(1)을 Keys.ENTER 뒤에 모두 넣어 주었다.

import time

    [....]

    inputbox.send_keys(Keys.ENTER)

    time.sleep(1)
    francis_list_url = self.browser.current_url
    self.assertRegex(francis_list_url, '/lists/.+')
    self.assertNotEqual(francis_list_url, edith_list_url)

                        
    [....]

추가로 함께 출력되던 아래의 에러도 함께 해결된다.


self.assertNotEqual(francis_list_url, edith_list_url) AssertionError: ‘http://localhost:8081/lists/the-only-list-in-the-world/’ == ‘http://localhost:8081/lists/the-only-list-in-the-world/’