python testing for flask

20

Upload: junyoung-park

Post on 12-Apr-2017

121 views

Category:

Software


1 download

TRANSCRIPT

파이썬 테스트

Unit testing

순서와 상관없이 독립적으로 실행 가능한 테스트

보통 컴포넌트나 모듈 단위을 �상으로 테스트

Functional testing

결과 값이 요구사항�로 나왔는지 확인

일종의 시나리오 테스트로 요구사항을 검증하는데 사용

Integration testing

단위 테스트를 통과한 기능이 정상적으로 동작하는지 검증

통합 모듈의 기능, 모듈 간의 인터페이스 검증

테스트 시나리오를 바탕으로한 실행방법과 예상결과를 정의 후 테스트

Friskweb API

회원가입 / 로그인JWT 인증 토큰 관련 테스트

서비스

리스트 받아오기, 디테일 읽어오기

구매

인증리스트 받아오기

각 인증 진행 테스트 (FB, KFTC)

구매 완료 확인

마이페이지

나의 인증현황 받아오기

주문내역 받아오기, 보고서 보기

회원탈퇴

기존의 테스트 코드

class AppTest(unittest.TestCase): def setUp(self): self.app = app.test_client() self.access_token = self.login()

def login(self): # 올바른 계정으로 로그인 시도 p = self.app.post('/signin', data={'id': 'ultratest' result = json.loads(p.data) self.assertEqual(result['e_msg'], ERROR.OK)

return result['access_token']

def test_signin(self): # 잘못된 아이디로 로그인 시도 p = self.app.post('/signin', data={'id': 'thereisnoidlikethis' result = json.loads(p.data) self.assertEqual(result['e_msg'], ERROR.ID_NOT_EXISTS)

기존 테스트 코드의 한계

test_back.py에 일괄적으로 때려박고 있음

각 모듈별로 정의된 기능을 따로 테스트하기 힘듬

테스트 시 출력되는 문구가 불친절해서 assert_helper를 또 만듬

테스트 모듈의 재사용이 힘듬

일부 모듈에 test fixture가 필요한 경우,클래스를 또 만들어서 setup(), teardown()을 지정

test/run.py를 파이참으로 실행해야 가능

pytestPyPy 팀이 meta‑tracing JIT 컴파일러라는 매우 복잡한 소프트웨어를 테스트하기 위해 직접 만들어온 프레임워크 (기존 테스팅 프레임워크들이 제�로만족을 못했기 때문에)

기능이 많고 개발이 매우 활성화 되어 있음

속도가 빠르고 병렬처리 가능

모듈화된 test fixture

assert rewriting

테스트 케이스 매개변수화

unittest, doctest도 함께 지원

간단히 비교해보자 ‑ unittest

import unittest

class TruthTest(unittest.TestCase): def testTrue(self): assertEqual(True, 1)

def testFalse(self): assertEqual(False, 0)

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

unittest를 import 해야한다

쓸데없이 assertEqual 함수를 권고한다

간단히 비교해보자 ‑ pytest

def testTrue(self): assert True == 1

def testFalse(self): assert False == 0

??!

pytest에 �한 소개https://github.com/pytest‑dev

pytest

pytest tests/test_app.pypytest backend/pytest backend/b2cpytest

test_, 또는 _test가 붙은 파이썬 파일을 알아서 읽는다.

setup.py # your setuptools Python package metadatamypkg/ __init__.py appmodule.py ... test/ test_app.py ...

pytest fixtures

# 모듈 내에서 사용하도록 설정@pytest.fixture(scope="module")

# 세션에서 사용하도록 설정@pytest.fixture(scope="session")

unittest의 Setup(), Teardown() function과 같은 역할

테스트의 전처리, 후처리 작업을 수행함

예를 들면, DB Connection

pytest fixtures

import pytest

@pytest.fixturedef smtp(): import smtplib return smtplib.SMTP("merlinux.eu")

def test_ehlo(smtp): response, msg = smtp.ehlo() assert response == 250 assert 0 # for demo purposes

fixture function을 decorator를 통해 등록하고 사용 가능.

pytest mark

@pytest.mark.skip(reason="test unnecessary")def test_the_unknown(): ...

각 테스트 모듈에 마킹(?) 할 수 있다.이렇게 하면 실패해도 그냥 스킵하고 넘어간다!

@pytest.mark.xfail(run=False)def test_function(): ...

당연히 실패할 테스트를 작성하고 xfail() 이라고 마킹!http://doc.pytest.org/en/latest/skipping.html

pytest monkeypatching

몽키패치란?

일반적인 의미는 런타임에서 모듈, 변수를 변경하는 것을 의미

테스트환경에서 몽키패치는?

올바른 동작을 보장하기 위해 오류가 발생하는 외부 데이터 소스에 �한 데이터 호출을 테스트해야할 때 사용 (전역설정, 네트워크 액세스 등)주로 파이썬과 같은 동적 프로그래밍 언어에서 사용

Refactoring

쉬운 유닛 테스트를 위해 Factory pattern을 적용해라

모듈 단위로 blueprint를 등록해라.

configuration을 import에 쓰지마라

Application Factory Pattern

def create_app(config_filename): app = Flask(__name__) configure_app(app)

from yourapplication.model import db db.init_app(app)

from yourapplication.views.admin import admin from yourapplication.views.frontend import frontend app.register_blueprint(admin) app.register_blueprint(frontend)

return app

fixture에 등록하여 구조적으로 테스트 가능

Configuration

from config import configure_app

app = Flask(__name__)configure_app(app, 'develop')

class Config(object): DEBUG = False TESTING = False DATABASE_URI = 'sqlite://:memory:'

class ProductionConfig(Config): DATABASE_URI = 'mysql://user@localhost/foo'

class DevelopmentConfig(Config): DEBUG = True

class TestingConfig(Config): TESTING = True

Configuration

config = { "default": "config.DevelopmentConfig", "development": "config.DevelopmentConfig", "production": "config.ProductionConfig", "testing": "config.TestingConfig"}

def configure_app(app, settings): app.config.from_object(config[settings])

개발 / 프로덕션 / 테스트 환경을 마음�로 설정 가능

Exception / Error handling

모든 메세지를 error.py에 하드코딩하는 것이 아니라에러코드에 �한 메세지로 인터페이스화

def bad_request(message): response = jsonify({'status': 'bad request', 'message' response.status_code = 400 return response

def unauthorized(message): response = jsonify({'status': 'unauthorized', 'message' response.status_code = 401 return response def not_found(message): response = jsonify({'status': 'not found', 'message': message}) response.status_code = 404 return response