python pytest!
pytest
def inc(x):
return x + 1
def test_answer():
assert inc(3) == 5
함수, 파일명에 _test, test_
클래스명에 Test...
문자열이 들어가 있으면 pytest 가 자동으로 테스트 함수임을 감지한다.
pytest --version
# pytest 8.3.1
pytest my_python.py
# ================== test session starts ===================
# platform darwin -- Python 3.10.8, pytest-8.3.1, pluggy-1.5.0
# rootdir: /Users/gojiyong/PycharmProjects/pythonProject
# collected 0 items
# ================= no tests ran in 0.00s ==================
# ERROR: file or directory not found: my_python.py
@pytest.mark.parametrize
여러개의 입력 파라미터로 지정할 수 있다.
@pytest.mark.parametrize("input, expected", [
(1, 2),
(2, 3),
(3, 4),
])
def test_increment(input, expected):
assert input + 1 == expected
@pytest.mark.skip
테스트 진행하지 않고 skip
@pytest.mark.skip(reason="not implemented yet")
def test_not_implemented():
assert False
@pytest.mark.skipif
skip_flag = True
@pytest.mark.skipif(skip_flag, reason="feature flag is disabled")
def test_skip_flag():
assert True
@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires Python 3.7 or higher")
def test_python_version():
assert True
@pytest.mark.skipif(os.getenv('SKIP_TEST') == 'true', reason="SKIP_TEST environment variable is set")
def test_skip_based_on_env_var():
assert True
외부 의존성에 맞춰 테스트
def is_service_available():
try:
response = requests.get("https://example.com")
return response.status_code == 200
except requests.RequestException:
return False
@pytest.mark.skipif(not is_service_available(), reason="external service is not available")
def test_external_service():
assert True
@pytest.fixture
모든 테스트에 필요한 공통 설정을 입력 파라미터로 지정할 수 있다.
@pytest.fixture
scope
별로 공통설정에서 반환한 값이 공유될 수 있다.
# 공통 설정 정의하기
@pytest.fixture
def sample_data():
return {"key": "value"}
def test_sample_data(sample_data):
assert sample_data["key"] == "value"
# 여러 공통 설정가져오기
@pytest.fixture
def user():
return {"username": "test_user"}
@pytest.fixture
def password():
return "secure_password"
def test_user_login(user, password):
assert user["username"] == "test_user"
assert password == "secure_password"
# 자동으로 모든 공통코드 수행하기
@pytest.fixture(autouse=True)
def auto_setup():
print("Automatically setting up")
def test_auto_setup_1():
assert True
def test_auto_setup_2():
assert True
# 공통 설정 연계
@pytest.fixture
def username():
return "test_user"
@pytest.fixture
def user(username):
return {"username": username}
def test_user(user):
assert user["username"] == "test_user"
fixture 와 yield
테스트 수행시 공통적인 setup & teardown(설정 & 해제)
작업을 @pytest.fixture
를 통해 정의할 수 있다.
file 열기, file 반남 형태의 테스트를 수행할 때 자주 사용함.
@pytest.fixture
def setup_and_teardown():
# setup code
data = {"key": "value"}
yield data # 테스트 함수에 data 전달
# teardown code
print("Teardown")
def test_setup_and_teardown(setup_and_teardown):
assert setup_and_teardown["key"] == "value"
setup code
에서 데이터를 가져오고, 테스트가 수행 완료된 후 teardown code
를 수행하여 후처리를 진행한다.
fixture scope
@pytest.fixture
scope 옵션은 네 가지 범위를 지원한다.
- function (기본값): 함수 내에서만 사용 가능
- class: 클래스 내부 정의된 테스트 함수간 공유
- module: 파일내부 정의된 테스트 함수간 공유
- package: 패키지(폴더)내부 정의된 테스트 함수간 공유
- session: 테스트 진행동안 공유
# scope=function 함수가 종료되면 파괴됨
@pytest.fixture(scope="function")
def resource():
return []
def test_function_scope_1(resource):
resource.append(1)
assert resource == [1]
def test_function_scope_2(resource):
resource.append(2)
assert resource == [2]
# scope=class, 클래스 외부로 나가면 파괴됨
@pytest.fixture(scope="class")
def resource():
return []
class TestClassScope:
def test_class_scope_1(self, resource):
resource.append(1)
assert resource == [1]
def test_class_scope_2(self, resource):
resource.append(2)
assert resource == [1, 2]
# scope=module, 모듈 외부로 나가면 파괴됨
@pytest.fixture(scope="module")
def resource():
return []
def test_module_scope_1(resource):
resource.append(1)
assert resource == [1]
def test_module_scope_2(resource):
resource.append(2)
assert resource == [1, 2]
@pytest.mark.usefixtures
테스트 함수 매개변수로 @pytest.fixture
로 정의한 공용설정 메서드를 삽입해야 했지만
@pytest.mark.usefixtures
를 사용하면 테스트 함수 위에 decorator 만 추가해주면 된다.
대신 공통 설정에 대한 값은 가져올 수 없다.
# 테스트 함수에서 사용하기
@pytest.fixture
def setup_data():
print("Setting up data")
@pytest.mark.usefixtures("setup_data")
def test_example():
assert True # Fixture setup_data is used, but not directly referenced in the function
# 클래스 테스트 함수에서 사용하기
@pytest.fixture
def setup_data():
print("Setting up data")
@pytest.fixture
def setup_database():
print("Setting up database")
@pytest.mark.usefixtures("setup_data", "setup_database")
class TestMultipleFixtures:
def test_method_1(self):
assert True
def test_method_2(self):
assert True
pytest-timeout
pip install pytest-timeout
pytest.ini
파일 설정 하여 모든 테스트에 timeout 관련 설정을 할 수 있다.
[pytest]
markers =
slow: 느린 테스트
timeout = 5 # 기본 타임아웃 설정 (필요 시)
@pytest.mark.timeout
해당 시간안에 테스트가 종료되지 않을 경우 오류로 판단.
@pytest.mark.timeout(2)
def test_with_timeout():
time.sleep(1) # 이 테스트는 성공
assert True
@pytest.mark.timeout(2)
def test_with_timeout_failure():
time.sleep(3) # 이 테스트는 실패
assert True
@pytest.mark.xfail
실패해도 결과가 실패로 간주되지 않는다
실패했을 때
failed
로 처리되지 않고ignored
로 처리됨
@pytest.mark.xfail
def test_not_yet_implemented():
assert False