업데이트(2018.04.16): 내용을 조금 수정하였습니다.

python에서 HttpResponse를 이용해 간단하게 Http요청 응답을 테스트하는 방법을 알아보자


환경 및 선수조건

  • Python
  • Django에 대한 기본 사용 및 이해
  • Selenium


소개

TDD를 공부하면서 프로젝트를 진행하기 때문에 현재 어떠한 일들을 구현할 때 기능 테스트를 하게된다. 그러한 기능 테스트를 진행하면서 이제 Http요청을 보내고 응답을 하였을 때 그 응답의 결과에 어떠한 특정한 문자열이 있는걸 확인할 때 본인은 html을 직접 만들어서 template를 만들고 응답해주는 코드를 작성하려 하였는데 더 쉬운 방법이 있어서 포스팅을 하려고 한다.


HttpRequest와 HttpResponse는?

  • HttpRequest: 요청에 대한 메타정보를 가지고 있는 객체
  • HttpResponse: 응답에 대한 메타정보를 가지고 있는 객체


상황 가정

홈페이지를 열었을 때 “돈까스 모임”이라는 모임의 텍스트가 있어야 한다고 가정을 하고 selenium을 통해 테스트를 해봅시다.


HttpResponse에 대한 예제 및 테스트

urls.py 코드 작성

urls.py는 장고에서 특정 url에 대한 요청을 어떤 함수나 클래스로 매핑해서 연결시켜주는 역할을 하는 부분입니다. 여기에서는 어떤 요청이던지간에 views.homepage의 함수로 연결되게 해두었습니다.

urls.py

from django.conf.urls import url
from django.contrib import admin
from moim import views

urlpatterns = [
    url(r'^$', views.homepage, name='home'),
    url(r'^admin/', admin.site.urls),
]


views.py 코드 작성

views.py는 urls.py에서 라우팅 되어온 요청에 대해서 처리하고 그에 따른 결과를 응답해주는 부분이 작성되는 곳입니다.

views.py

from django.shortcuts import render
from django.http import HttpResponse


def homepage(request):
    return HttpResponse('돈까스 모임')


테스트 코드 작성

이제 urls.py에서 views.py의 특정 함수(이 본문의 경우에는 homepage 함수)로 연결해주고 views.py의 homepage 함수에서 “돈까스 모임”이라고 응답을 해주므로 이제 확인하는 테스트 코드를 작성해보겠습니다.

homepage_test.py

def test_checking_prepared_environment_with_selenium():

    #드라이버를 설치하고 가져오는 코드
    driver.get("http://localhost:8000")
    assert '돈까스 모임' in driver.page_source
    driver.close()


테스트 및 실행

장고 서버를 실행시키고 테스트를 돌려보도록 하겠습니다.

$ python manage.py runserver # 장고 서버 실행
$ pytest homepage_test.py # 테스트 코드 실행


다음처럼 테스트가 성공적으로 실행됨을 확인 할 수 있습니다.

Done Test


참고자료

업데이트(2019.02.19): 파일열기모드 관련 내용 추가

python에서 with문의 용도와 쓰임을 알아보자


소개

기본적으로 거의 모든 프로그래밍 언어가 파일 입출력을 지원하며(어찌보면 당연한 이야기인가?…) 그러한 파일 입출력을 할 때 해당 파일을 위해 open과 close를 해줘야한다.

그러한 부분이 python에도 존재하며 혹시나 우리가 했을 법한 실수인 close를 해주는 부분을 빼먹을 수도 있기에 하나의 with문으로 묶어서 사용 할 수 있다.


기본적인 사용법

  • 기본적인 사용법은 with expression as target: suite의 형태로 사용하면 된다.


다음 아래와 같은 코드를

file_data = open('file.txt')
print(file_data.readline(), end="")
file_data.close()

아래처럼 바꿀 수 있다.

with open('file.txt') as file_data:
    # 기본적으로 사용하는 함수를  with문 안에 사용하면 되며
    # with문을 나올 때 close를 자동으로 불러줍니다.
    print(file_data.readline(), end="")


파일 열기 모드

  • 파일열기모드: 파일열기모드란 파일을 Binary형태로 읽을지 아니면 인코딩단위로 읽을지, 파일을 읽을건지 쓸건지 아니면 동시에 할건지에 대한 부분을 정하는 지시자라고 볼 수 있습니다.

  • r: 읽기 모드, 파일을 읽을 때 사용합니다.
  • w: 쓰기 모드, 파일에 쓸 때 사용하며 파일이 이미 동일한 이름으로 존재한다면 덮어씁니다.
  • a: 추가 모드, 존재하는 파일에 추가할 때 사용하며 파일이 없다면 생성합니다.
  • r+, w+, a+: 읽기모드 + 쓰기모드, w+a+의 차이는 위와 같습니다.
  • rb, wb, ab, rb+, wb+, ab+: 각각의 모드들은 위와 동일하나 Binary 포맷으로 읽거나 쓰는걸 진행합니다.

쓰기(Write)

with open('file.txt', 'w') as file_data:
    file_data.write("First\n")
    file_data.write("Second")

읽기(Read)

with open('file.txt', 'r') as file_data:
    for line in file_data:
        print(line)

추가(Append)

with open('file.txt', 'a') as file_data:
    file_data.write("Third\n")


참고자료

pytest를 설치는 하였고 이제 Exception을 처리하는 방법에 대해서 알아보자


환경 및 선수조건


기본적인 사용법

  • Exception의 오류를 잡기 위해서 pytest에서는 pytest.raises([Exception])이라는 함수를 통해서 실행시킵니다. 바로 코드를 보도록 하겠습니다.
  • 아주 간단한 코드로 with문을 참고하시면 ()안에 있는 Exception이 발생하는지를 확인하는 코드입니다. with문 안에 1/0의 코드를 통해서 해당 Exception을 발생시킵니다.

test_zero_division.py

import pytest


def test_zero_division():
    # with문 괄호에 있는 Exception이 해당 block에서 일어나는지 확인하는 코드
    with pytest.raises(ZeroDivisionError):
        1 / 0


이제 코드를 작성하였으니 실행시켜봅시다.

Run Test


참고자료

pytest를 설치하고 간단하게나마 테스트하는 방법에 대해서 포스팅해보려 한다.


환경 및 선수조건

  • Python 3.x만 설치되어있으면 가능합니다.
  • (선택) pyenv, virtualenv의 사용경험 및 방법 숙지
  • (선택) virtualenv의 이름은 “pytest_practice”로 하고 진행


설치

다음 아래와 같이 pip를 통해서 pytest를 설치합니다.

$ pip install pytest


기본적인 사용법

파일생성 및 기본 테스트 예제

다음 아래과 같이 기본적인 샘플 코드를 만들고 프로젝트 폴더 안에 추가를 합니다.

simple_test.py

def test_simple_test():
  assert 1

아주 기본적인 테스트로 “assert 1”이 있기때문에 테스트를 통과하게 됩니다. 이제 다음으로 터미널에서 테스트를 진행해보도록 하겠습니다. 아래의 명령문을 입력해주면 simple_test.py에 있는 코드에서 test로 시작되는 함수들을 찾아서 테스트를 진행합니다.

$ pytest simple_test.py

다음 아래는 그 테스트 결과입니다.

first test


테스트 오류 확인 예제

다음으로는 이제 테스트 오류가 어떻게 나는지 확인하기 위해서 아래와 같은 새로운 파일을 또 추가해 보겠습니다.

simple_another_test.py

def test_simple_another_test():
    assert 1

def test_simple_another_test_fail():
    assert 0

자 이제 그러면 테스트를 또 돌려봅시다. 이제는 2개의 파일이 있기 때문에 pytest만 명령어 창에 입력하도록 합시다.

$ pytest

그러면 다음과 같이 테스트 결과가 나오게 됩니다.

second test


테스트 결과만 확인

다음과 같이 -q 옵션을 명령어에 추가해서 최종적인 테스트 결과만 확인도 가능합니다.

$ pytest -q

아래는 실행해본 결과입니다.

third test

pytest를 썼을 때의 장점을 http://halfcooked.com/presentations/pyconau2013/why_I_use_pytest.html 의 링크에서 번역해 간단하게나마 정리를 해보았다.


Unit Testing이란?

  • Unit Testing이란 어플리케이션이나 모듈의 각각 유닛들이 작성한대로 작성하는지 확인하는 반복적인 작업이다.

  • Unit Testing의 핵심은 각각 테스트들이 서로 분리되어 있으며, 실행은 자동화되고, 테스트들은 당신이 만든 어플리케이션의 일부와 같은 부분을 실행한다는 것이다.


Unit Test를 왜 해야 할까?

다른 이유보다 앞서서 하는 이유는 “내 코드가 잘 작동하는지 확인하기 위해서”라는 것은 모두다 알고 계실겁니다.

Unit Test는 우리가 “어떻게” 코드를 작성할지 생각하는데 도움을 주게되며 나아가 테스트를 추가함을 통해서 당신의 코드를 줄일 수 있게되고 이러한 점들은 당신이 이해하고 테스트하는데 다시 또 도움을 주게 됩니다.

많은 작업을 하는 코드를 테스트 하는것은 어려우며 또한 디버깅하기도 어렵다. 이 문제의 해결은 코드가 많은 작업을 하지 않도록 하게 하는 것이며 그렇기에 함수 하나는 하나의 기능만 하도록 하고 이를 테스트 하게 하는것이다.

“그리고”라는 말을 표현해서 코드를 설명해야 한다면 그 코드는 줄일 수 있어야 한다.(하나의 함수는 하나의 기능만을 구현해야 하기 때문에)

Unit Test의 다른 장점로는 문제를 찾기 쉽다는 점, 변화를 가능하게 한다는 점, 디자인을 개선시키고 통합을 단순화 할 수 있다는 점들이 있다.


Unit Test 라이브러리들

테스트 라이브러이에는 대표적으로 unittest(파이썬 기본 내장 모듈)와 pytest가 있는데 저 본문에는 pytest를 선호한다고 나와있다.

그 이유는 코드를 비교적 더 간단하게 만들 수 있고 필요할 떄 더 많은 기능들을 강력하게 제공해주기 때문이라고 한다.

아래와 같은 코드를

from parse_conn import parse_connection
import unittest

class InvalidInputs(unittest.TestCase):
    def testNoAt(self):
        """parse_connection should raise an exception for an invalid connection string"""
        self.assertRaises(ValueError, parse_connection, 'invalid uri')

if __name__ == "__main__":
    unittest.main()

다음과 같이 바꿀 수 있다고 한다.

from parse_conn import parse_connection
import py.test

def test_not_at():
    py.test.raises(ValueError, parse_connection, 'invalid uri')

한눈에 봐도 비교적 코드가 많이 간결해졌음을 알 수 있다.


그러면 Unit Testing을 어떻게 시작해야할까?

테스팅을 할 수 있는 가장 쉬운 방법은 버그를 수정하는 방법이다.

첫번째로, 버그를 발견하고 그다음에 버그를 고칠 수 있는 최소한의 코드를 작성하고 마지막으로 테스트를 다 통과 할 때까지 코드를 수정하는 것이다.

앞서 말한것처럼 해서 테스팅을 시작 할 수 있고 이제 새로 작동해야하는 기능을 추가 할 때 최소한의 테스트를 만들고 그 테스트를 통과하는 코드들을 완성하는 방향으로 시작하면 된다.


참고자료