Pytest 시작하기
pytest 설치
pytest는 Python 3.8+ 또는 PyPy3가 필요합니다.
명령줄에서 다음 명령을 실행하세요:
pip install -U pytest
올바른 버전이 설치되었는지 확인:
$ pytest --version
pytest 8.4.1
첫 번째 테스트 작성
test_sample.py
라는 새 파일을 만들고, 함수와 테스트를 포함시키세요:
# test_sample.py 내용
def func(x):
return x + 1
def test_answer():
assert func(3) == 5
테스트 실행:
$ pytest
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-8.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
collected 1 item
test_sample.py F [100%]
================================= FAILURES =================================
_______________________________ test_answer ________________________________
def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
test_sample.py:6: AssertionError
========================= short test summary info ==========================
FAILED test_sample.py::test_answer - assert 4 == 5
============================ 1 failed in 0.12s =============================
[100%]
는 모든 테스트 케이스 실행의 전체 진행률을 나타냅니다. 완료 후, func(3)
이 5를 반환하지 않기 때문에 pytest는 실패 보고서를 보여줍니다.
참고
assert
문을 사용하여 테스트 기대치를 검증할 수 있습니다. pytest의 고급 assertion 분석 기능은 assert 표현식의 중간 값을 지능적으로 보고하므로 JUnit 레거시 메서드의 많은 이름을 피할 수 있습니다.
여러 테스트 실행
pytest는 현재 디렉토리와 하위 디렉토리에서 test_*.py
또는 *_test.py
형태의 모든 파일을 실행합니다. 더 일반적으로는 표준 테스트 검색 규칙을 따릅니다.
특정 예외가 발생하는지 검증
raises
헬퍼를 사용하여 코드가 예외를 발생시키는지 검증:
# test_sysexit.py 내용
import pytest
def f():
raise SystemExit(1)
def test_mytest():
with pytest.raises(SystemExit):
f()
"quiet" 보고 모드로 테스트 함수 실행:
$ pytest -q test_sysexit.py
. [100%]
1 passed in 0.12s
참고
-q/--quiet
플래그는 이 예제와 다음 예제들에서 출력을 간략하게 유지합니다.
예상되는 예외에 대한 더 자세한 지정은 예상 예외에 대한 Assertions (opens in a new tab)를 참조하세요.
클래스에서 여러 테스트 그룹화
여러 테스트를 개발하면 클래스로 그룹화하고 싶을 수 있습니다. pytest를 사용하면 하나 이상의 테스트를 포함하는 클래스를 쉽게 만들 수 있습니다:
# test_class.py 내용
class TestClass:
def test_one(self):
x = "this"
assert "h" in x
def test_two(self):
x = "hello"
assert hasattr(x, "check")
pytest는 Python~~ 테스트 검색 규칙에 따라 모든 테스트를 검색하므로 ~~test_
접두사가 있는 함수를 모두 찾습니다. 어떤 것도 서브클래스할 필요가 없지만, 클래스에 Test
접두사를 붙여야 합니다. 그렇지 않으면 클래스가 건너뛰어집니다. 파일명을 전달하여 모듈을 간단히 실행할 수 있습니다:
$ pytest -q test_class.py
.F [100%]
================================= FAILURES =================================
____________________________ TestClass.test_two ____________________________
self = <test_class.TestClass object at 0xdeadbeef0001>
def test_two(self):
x = "hello"
> assert hasattr(x, "check")
E AssertionError: assert False
E + where False = hasattr('hello', 'check')
test_class.py:8: AssertionError
========================= short test summary info ==========================
FAILED test_class.py::TestClass::test_two - AssertionError: assert False
1 failed, 1 passed in 0.12s
첫 번째 테스트는 통과했고 두 번째는 실패했습니다. assertion의 중간 값을 쉽게 볼 수 있어 실패 이유를 이해하는 데 도움이 됩니다.
클래스에서 테스트를 그룹화하는 것은 다음과 같은 이유로 유익할 수 있습니다:
- 테스트 조직화
- 특정 클래스의 테스트만을 위한 픽스처 공유
- 클래스 레벨에서 마크 적용 및 모든 테스트에 암시적으로 적용
클래스 내에서 테스트를 그룹화할 때 알아야 할 점은 각 테스트가 클래스의 고유한 인스턴스를 가진다는 것입니다. 각 테스트가 동일한 클래스 인스턴스를 공유하는 것은 테스트 격리에 매우 해로우며 나쁜 테스트 관행을 조장할 것입니다. 이는 아래에 설명되어 있습니다:
# test_class_demo.py 내용
class TestClassDemoInstance:
value = 0
def test_one(self):
self.value = 1
assert self.value == 1
def test_two(self):
assert self.value == 1
$ pytest -k TestClassDemoInstance -q
.F [100%]
================================= FAILURES =================================
______________________ TestClassDemoInstance.test_two ______________________
self = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef0002>
def test_two(self):
> assert self.value == 1
E assert 0 == 1
E + where 0 = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef0002>.value
test_class_demo.py:9: AssertionError
========================= short test summary info ==========================
FAILED test_class_demo.py::TestClassDemoInstance::test_two - assert 0 == 1
1 failed, 1 passed in 0.12s
클래스 레벨에서 추가된 속성은 클래스 속성이므로 테스트 간에 공유됩니다.
기능 테스트를 위한 고유 임시 디렉토리 요청
pytest는 고유 임시 디렉토리와 같은 임의의 리소스를 요청하기 위한 내장 픽스처/함수 인수를 제공합니다:
# test_tmp_path.py 내용
def test_needsfiles(tmp_path):
print(tmp_path)
assert 0
테스트 함수 시그니처에 tmp_path
이름을 나열하면 pytest가 테스트 함수 호출을 수행하기 전에 픽스처 팩토리를 찾아 호출하여 리소스를 생성합니다. 테스트가 실행되기 전에 pytest는 테스트 호출마다 고유한 임시 디렉토리를 생성합니다:
$ pytest -q test_tmp_path.py
F [100%]
================================= FAILURES =================================
_____________________________ test_needsfiles ______________________________
tmp_path = PosixPath('PYTEST_TMPDIR/test_needsfiles0')
def test_needsfiles(tmp_path):
print(tmp_path)
> assert 0
E assert 0
test_tmp_path.py:3: AssertionError
--------------------------- Captured stdout call ---------------------------
PYTEST_TMPDIR/test_needsfiles0
========================= short test summary info ==========================
FAILED test_tmp_path.py::test_needsfiles - assert 0
1 failed in 0.12s
임시 디렉토리 처리에 대한 자세한 정보는 임시 디렉토리와 파일 (opens in a new tab)에서 확인할 수 있습니다.
다음 명령으로 어떤 종류의 내장 pytest 픽스처가 존재하는지 확인하세요:
pytest --fixtures # 내장 및 사용자 정의 픽스처 표시
이 명령은 -v
옵션이 추가되지 않는 한 선행 _
가 있는 픽스처는 생략합니다.
계속 읽기
고유한 워크플로에 맞게 테스트를 사용자 정의하는 데 도움이 되는 추가 pytest 리소스를 확인하세요:
- "pytest 호출 방법" (opens in a new tab) - 명령줄 호출 예제
- "기존 테스트 스위트와 pytest 사용 방법" (opens in a new tab) - 기존 테스트 작업
- "속성으로 테스트 함수 마킹 방법" (opens in a new tab) - pytest.mark 메커니즘 정보
- "픽스처 참조" (opens in a new tab) - 테스트에 기능적 기준선 제공
- "플러그인 작성" (opens in a new tab) - 플러그인 관리 및 작성
- "좋은 통합 관행" (opens in a new tab) - virtualenv 및 테스트 레이아웃