Python Language
py.test
수색…
py.test 설정하기
py.test
는 Python에서 사용할 수있는 여러 타사 테스트 라이브러리 중 하나입니다. pip
와 함께 설치할 수 있습니다.
pip install pytest
테스트 코드
projectroot/module/code.py
에서 추가 함수를 테스트한다고 가정 projectroot/module/code.py
.
# projectroot/module/code.py
def add(a, b):
return a + b
테스트 코드
projectroot/tests/test_code.py
에 테스트 파일을 projectroot/tests/test_code.py
. 파일 은 test_
로 시작해야 테스트 파일로 인식됩니다.
# projectroot/tests/test_code.py
from module import code
def test_add():
assert code.add(1, 2) == 3
테스트 실행하기
projectroot
에서 py.test
를 실행하면됩니다.
# ensure we have the modules
$ touch tests/__init__.py
$ touch module/__init__.py
$ py.test
================================================== test session starts ===================================================
platform darwin -- Python 2.7.10, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
rootdir: /projectroot, inifile:
collected 1 items
tests/test_code.py .
================================================ 1 passed in 0.01 seconds ================================================
실패한 테스트
실패한 테스트는 무엇이 잘못되었는지에 대한 유용한 결과를 제공합니다.
# projectroot/tests/test_code.py
from module import code
def test_add__failing():
assert code.add(10, 11) == 33
결과 :
$ py.test
================================================== test session starts ===================================================
platform darwin -- Python 2.7.10, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
rootdir: /projectroot, inifile:
collected 1 items
tests/test_code.py F
======================================================== FAILURES ========================================================
___________________________________________________ test_add__failing ____________________________________________________
def test_add__failing():
> assert code.add(10, 11) == 33
E assert 21 == 33
E + where 21 = <function add at 0x105d4d6e0>(10, 11)
E + where <function add at 0x105d4d6e0> = code.add
tests/test_code.py:5: AssertionError
================================================ 1 failed in 0.01 seconds ================================================
테스트 설비 소개
더 복잡한 테스트는 테스트 할 코드를 실행하기 전에 설정해야 할 경우가 있습니다. 테스트 기능 자체에서이 작업을 수행 할 수는 있지만 대규모 테스트 기능으로 인해 결국 설정이 중지되고 테스트가 시작되는 위치를 알기가 어렵습니다. 다양한 테스트 기능간에 중복 된 설정 코드를 많이 얻을 수도 있습니다.
우리의 코드 파일 :
# projectroot/module/stuff.py
class Stuff(object):
def prep(self):
self.foo = 1
self.bar = 2
테스트 파일 :
# projectroot/tests/test_stuff.py
import pytest
from module import stuff
def test_foo_updates():
my_stuff = stuff.Stuff()
my_stuff.prep()
assert 1 == my_stuff.foo
my_stuff.foo = 30000
assert my_stuff.foo == 30000
def test_bar_updates():
my_stuff = stuff.Stuff()
my_stuff.prep()
assert 2 == my_stuff.bar
my_stuff.bar = 42
assert 42 == my_stuff.bar
이것들은 꽤 간단한 예제이지만, Stuff
객체가 더 많은 셋업을 필요로한다면, 다루기 힘들어 질 것입니다. 우리는 테스트 케이스 사이에 중복 된 코드가 있다는 것을 알았으므로 먼저이를 별도의 함수로 리팩토링하자.
# projectroot/tests/test_stuff.py
import pytest
from module import stuff
def get_prepped_stuff():
my_stuff = stuff.Stuff()
my_stuff.prep()
return my_stuff
def test_foo_updates():
my_stuff = get_prepped_stuff()
assert 1 == my_stuff.foo
my_stuff.foo = 30000
assert my_stuff.foo == 30000
def test_bar_updates():
my_stuff = get_prepped_stuff()
assert 2 == my_stuff.bar
my_stuff.bar = 42
assert 42 == my_stuff.bar
이것은 더 나아 보이지만 우리는 여전히 my_stuff = get_prepped_stuff()
호출이 우리의 테스트 함수를 혼란 my_stuff = get_prepped_stuff()
합니다.
py.test 구출 구조!
Fixture는 테스트 설정 기능의 훨씬 강력하고 유연한 버전입니다. 우리가 여기서 활용하는 것보다 훨씬 많은 일을 할 수 있지만, 한 번에 한 걸음 씩 나아갈 것입니다.
먼저 get_prepped_stuff
를 prepped_stuff
라는 조명기로 변경합니다. 나중에 테스트 함수에서 조명기가 사용되는 방법 때문에 동사가 아닌 명사로 조명기의 이름을 지정하려고합니다. @pytest.fixture
는이 특정 함수가 정규 함수가 아닌 고정 장치로 처리되어야 함을 나타냅니다.
@pytest.fixture
def prepped_stuff():
my_stuff = stuff.Stuff()
my_stuff.prep()
return my_stuff
이제 우리는 fixture를 사용하도록 테스트 함수를 업데이트해야합니다. 이는 조명기 이름과 정확하게 일치하는 매개 변수를 정의에 추가하여 수행됩니다. py.test가 실행되면 테스트를 실행하기 전에 조명기를 실행 한 다음 해당 매개 변수를 통해 조명기의 반환 값을 테스트 함수로 전달합니다. (조명기는 값을 리턴 할 필요 가 없으며, 외부 자원 호출, 파일 시스템 정렬, 데이터베이스에 값 입력, 설정 테스트에 필요한 모든 것)와 같은 다른 설정 작업을 수행 할 수 있습니다.
def test_foo_updates(prepped_stuff):
my_stuff = prepped_stuff
assert 1 == my_stuff.foo
my_stuff.foo = 30000
assert my_stuff.foo == 30000
def test_bar_updates(prepped_stuff):
my_stuff = prepped_stuff
assert 2 == my_stuff.bar
my_stuff.bar = 42
assert 42 == my_stuff.bar
이제 우리는 명사로 이름을 지은 이유를 알 수 있습니다. 하지만 my_stuff = prepped_stuff
라인은 꽤 쓸모가 없으므로 대신 prepped_stuff
직접 사용하도록합시다.
def test_foo_updates(prepped_stuff):
assert 1 == prepped_stuff.foo
prepped_stuff.foo = 30000
assert prepped_stuff.foo == 30000
def test_bar_updates(prepped_stuff):
assert 2 == prepped_stuff.bar
prepped_stuff.bar = 42
assert 42 == prepped_stuff.bar
이제 우리는 비품을 사용하고 있습니다! 우리는 조명기의 범위를 변경함으로써 더 나아갈 수 있습니다 (그래서 그것은 테스트 기능마다 한 번만 실행되는 것이 아니라 테스트 모듈 또는 테스트 스위트 실행 세션마다 한 번만 실행됩니다), 다른 조명기를 사용하는 조명기를 구축하고 조명기를 매개 변수화함으로써 (조명기 및 모든 해당 조명기를 사용하는 테스트는 조명기에 지정된 각 매개 변수에 대해 한 번 여러 번 실행됩니다.) 앞에서 언급했듯이 조명기 모듈에서 값을 읽는 조명기는 조명기가 일반 설치 기능보다 훨씬 강력하고 유연성이 뛰어납니다.
검사가 끝나면 청소.
우리 코드가 커졌고 Stuff 객체가 특별한 정리가 필요하다고 가정 해 봅시다.
# projectroot/module/stuff.py
class Stuff(object):
def prep(self):
self.foo = 1
self.bar = 2
def finish(self):
self.foo = 0
self.bar = 0
모든 테스트 함수의 맨 아래에 정리를 호출 할 수있는 코드를 추가 할 수 있지만 픽스쳐는이를 수행하는 더 좋은 방법을 제공합니다. 조명기에 함수를 추가하고이를 파이널 라이저 로 등록하면, 파이널 라이저를 사용하는 테스트가 완료된 후에 파이널 라이저 함수의 코드가 호출됩니다. 조명기의 범위가 하나의 함수 (모듈이나 세션과 같은)보다 큰 경우 범위의 모든 테스트가 완료된 후에 파이널 라이저가 실행되므로 모듈이 실행 완료되거나 전체 실행 세션이 끝난 후에 실행됩니다 .
@pytest.fixture
def prepped_stuff(request): # we need to pass in the request to use finalizers
my_stuff = stuff.Stuff()
my_stuff.prep()
def fin(): # finalizer function
# do all the cleanup here
my_stuff.finish()
request.addfinalizer(fin) # register fin() as a finalizer
# you can do more setup here if you really want to
return my_stuff
함수 내에서 파이널 라이저 함수를 사용하는 것은 언뜻보기에 이해하기 어렵습니다. 특히 복잡한 픽스처가있는 경우 더욱 그렇습니다. 대신에 yield fixture 를 사용하여 사람이 읽을 수있는 실행 흐름으로 동일한 작업을 수행 할 수 있습니다. 유일한 차이점은 대신 사용하는 것입니다 return
우리가 사용 yield
설치 완료 및 제어 테스트 기능으로 이동해야하는 고정 부분에서, 다음 이후에 모든 정리 코드를 추가 yield
. 우리는 또한 그것을 yield_fixture
py.test가 그것을 처리하는 방법을 안다.
@pytest.yield_fixture
def prepped_stuff(): # it doesn't need request now!
# do setup
my_stuff = stuff.Stuff()
my_stuff.prep()
# setup is done, pass control to the test functions
yield my_stuff
# do cleanup
my_stuff.finish()
그리고 이것으로 인스 트루먼 트 테스트 픽스쳐가 마무리되었습니다!
더 자세한 정보는 공식 py.test fixture 문서 와 공식 yield fixture documentation을보십시오.