Pytest 픽스쳐
픽스쳐는 모듈식이고, 확장성 있고, 유지 관리할 수 있는 테스트를 만드는 데 사용되는 pytest 도우미 함수입니다. 픽스쳐를 사용하여 데이터베이스 연결, 테스트 데이터 만들기 또는 테스트 실행 전에 필요한 시스템 상태 구성과 같은 테스트에 대한 사전 조건을 설정합니다. 테스트를 실행한 후 정리에 사용할 수도 있습니다.
pytest 픽스쳐의 주요 특징은 다음과 같습니다.
- 범위 제어: 픽스쳐는 픽스쳐가 호출되는 빈도를 결정하는
scope
매개 변수(예:function
,class
,module
또는session
)를 사용하여 서로 다른 범위를 포함하도록 구성할 수 있습니다. - 설정 및 해체의 처리: Pytest는 필요에 따라 자동으로 설정하고 분해하여 픽스쳐의 수명 주기를 관리합니다.
- 종속성 주입: 픽스쳐는 인수로 테스트 함수에 주입되므로 어떤 테스트가 어떤 픽스쳐에 의존하는지 명확하게 합니다.
- 재사용성 및 모듈성: 픽스쳐는 한 곳에서 정의할 수 있으며 여러 테스트 함수나 모듈 또는 프로젝트에서도 사용할 수 있습니다.
임시 파일 픽스쳐 만들기
파일과 상호 작용하는 테스트를 작성할 때 일반적으로 테스트 후 파일 시스템을 복잡하게 만들지 않는 임시 파일이 필요합니다. pytest를 사용하여 임시 파일을 설정하는 픽스쳐를 만들 수 있습니다. 픽스쳐는 Python의 tempfile
모듈을 사용하여 임시 파일을 안전하게 생성하여 로컬 환경에 영향을 주지 않고 사용하고 삭제할 수 있도록 합니다. (이 초기 버전의 픽스쳐에서는 delete=False
플래그로 인해 파일이 자동으로 삭제되지 않습니다. 나중에 파일 삭제를 다룹니다.)
픽스쳐는 다음과 같습니다.
import pytest
import tempfile
@pytest.fixture
def tmp_file():
def create():
# Create a named temporary file that persists beyond the function scope
temp = tempfile.NamedTemporaryFile(delete=False)
return temp.name
return create
이 설정에서 tmp_file()
은 픽스쳐 역할을 합니다. 픽스쳐의 이름은 테스트가 이를 참조하는 방법입니다. 픽스쳐 내에서 중첩된 함수 create()
는 픽스처를 설정할 때가 아니라 호출될 때만 파일을 만듭니다. 이렇게 하면 임시 파일이 생성되는 시기를 정확하게 제어할 수 있으며 타이밍 및 파일 상태가 중요한 테스트에서 유용합니다.
중첩된 함수 create()
내에서 임시 파일을 만든 다음 절대 경로를 반환합니다. 다음은 테스트가 작성한 픽스쳐를 사용하는 방법의 예입니다.
import os
def test_file(tmp_file):
path = tmp_file()
assert os.path.exists(path)
테스트는 픽스쳐의 이름을 인수로 지정하여 픽스쳐를 사용합니다. 간단한 사용 사례는 파일에 쓰거나 사용 권한 또는 소유권 변경과 같은 수정 작업을 수행하여 쉽게 확장할 수 있습니다.
범위 관리
pytest에서 설정 및 해체 루틴을 통해 테스트 리소스의 수명 주기를 관리하는 것은 깨끗하고 효율적인 테스트 환경을 유지하는 데 매우 중요합니다. 또한 각 테스트가 알려진 일관된 상태로 시작되도록 하여 테스트의 무결성을 보호하려고 합니다. 기본적으로 pytest 픽스쳐는 두 가지 방법으로 동작에 영향을 미치는 function
범위로 작동합니다.
- 테스트당 수명 주기: 픽스쳐의 반환 값은 해당 값을 사용하는 모든 테스트 함수에 대해 다시 계산되어 각 테스트가 새 상태로 작동하도록 합니다.
- 각 사용 후 정리: 필요한 정리 작업은 픽스쳐를 활용하는 각 테스트 후에 수행됩니다.
또한 Pytest를 사용하면 성능 및 리소스 사용을 최적화하기 위해 픽스쳐의 범위를 더 광범위하게 지정할 수 있습니다. 범위 지정은 데이터베이스 상태 관리와 같은 상황에서 또는 설정하는 데 시간이 많이 걸리는 복잡한 상태 설정이 있는 경우에 특히 유용합니다. 사용할 수 있는 네 가지 범위는 다음과 같습니다.
function
: 기본 범위, 픽스쳐는 테스트당 한 번 실행됩니다.class
: 픽스쳐는 테스트 클래스당 한 번 실행됩니다.module
: 모듈에 대해 한 번 실행됩니다.session
: 테스트 세션당 한 번 실행됩니다. 이 범위는 서비스 초기화 또는 데이터베이스 서버 시작과 같이 전체 테스트 세션 전체에서 유지해야 하는 비용이 많이 드는 작업에 유용합니다.
이 경우 한 번 실행하면 반환 값이 캐시됩니다. 따라서 “모듈”의 범위가 있는 픽스쳐는 테스트 모듈에서 여러 번 호출될 수 있지만 반환 값은 이를 호출한 첫 번째 테스트의 값입니다.
모듈 범위에서 tmp_file()
픽스쳐가 표시되는 방식은 다음과 같습니다.
import pytest
import tempfile
@pytest.fixture(scope="module")
def tmp_file():
def create():
temp = tempfile.NamedTemporaryFile(delete=False)
return temp.name
return create
정리 관리
tmp_file
픽스쳐를 지정하는 이전 코드는 임시 파일을 만들지만 테스트가 완료된 후에는 자동으로 정리를 처리하지 않습니다. 임시 파일이 남아 있지 않도록 하려면 pytest의 request
픽스쳐를 사용하여 정리 함수를 등록할 수 있습니다.
자동 정리를 포함하도록 tmp_file
고정을 수정하는 방법은 다음과 같습니다.
import pytest
import tempfile
import os
@pytest.fixture(scope="module")
def tmp_file(request):
# Create a temporary file that persists beyond the function scope
temp = tempfile.NamedTemporaryFile(delete=False)
def create():
# Returns the path of the temporary file
return temp.name
def cleanup():
# Remove the file after the tests are done
os.remove(temp.name)
# Register the cleanup function to be called after the last test in the module
request.addfinalizer(cleanup)
return create
request.addfinalizer()
를 사용하고 중첩 cleanup()
함수를 전달하면 범위에 따라 정리가 호출됩니다. 이 경우 범위는 module
이므로 모듈 pytest의 모든 테스트 후에는 해당 정리 함수를 호출합니다.
conftest.py 사용
테스트 파일에 픽스쳐를 포함하는 대신 픽스쳐를 conftest.py 파일에 저장할 수 있습니다. conftest.py의 모든 픽스쳐는 픽스쳐를 명시적으로 가져오지 않고도 동일한 디렉터리의 테스트에서 자동으로 사용할 수 있습니다.
기본 제공 픽스쳐 탐색
Pytest에는 테스트를 간소화하도록 설계된 많은 기본 제공 픽스쳐가 있습니다. 이러한 픽스쳐는 설치 및 정리를 자동으로 처리할 수 있으므로 테스트 관리 대신 테스트 사례를 작성하는 데 집중할 수 있습니다.
주요 기본 제공 픽스쳐는 다음과 같습니다.
cache
: 테스트 세션 간에 데이터를 저장하는 데 유용한 테스트 수준 캐시를 만들고 관리하는 데 사용됩니다.capsys
:stderr
및stdout
을 캡처하고 검사할 수 있으므로 콘솔 출력을 쉽게 검사하고 테스트할 수 있습니다.tmpdir
: 테스트 중에 만들고 사용해야 하는 파일에 대한 임시 디렉터리를 제공합니다.monkeypatch
: 개체, 함수 및 OS 환경의 동작과 값을 안전하게 수정하는 방법을 제공합니다.
테스트에서 monkeypatching의 역할
데이터베이스 또는 외부 API와 같은 외부 리소스와 긴밀하게 통합되는 코드 테스트는 관련된 종속성으로 인해 어려울 수 있습니다. monkey patching이라는 기술에는 테스트 실행 중에 시스템을 일시적으로 수정하여 외부 시스템에서 독립할 수 있도록 하며 테스트 중에 운영 체제 환경의 상태와 동작을 안전하게 변경할 수 있게 합니다.
다음은 monkeypatch
픽스쳐를 사용하여 os.path.exists()
함수를 재정의하는 방법의 예입니다.
import os
def test_os(monkeypatch):
# Override os.path.exists to always return False
monkeypatch.setattr('os.path.exists', lambda x: False)
assert not os.path.exists('/')
또는 개체 및 특성에 대한 직접 참조와 함께 setattr()
메서드를 사용할 수 있습니다.
def test_os(monkeypatch):
# Specify the object and attribute to override
monkeypatch.setattr(os.path, 'exists', lambda x: False)
assert not os.path.exists('/')
특성을 설정하고 메서드를 재정의하는 것 외에도, monkeypatch
픽스쳐는 환경 변수를 설정 및 삭제하고, 사전 값을 변경하고, 시스템 경로를 수정할 수 있습니다. monkeypatch
픽스쳐는 각 테스트 후 변경 내용을 자동으로 되돌리지만 monkeypatch
픽스쳐를 사용할 때는 여전히 주의해야 합니다. 사용 시 주의해야 하는 몇 가지 이유는 다음과 같습니다.
-코드 명확성 및 유지 관리: monkeypatch
를 과도하게 사용하거나 복잡한 방법으로 사용하면 테스트를 이해하고 유지 관리하기가 더 어려워질 수 있습니다. 테스트 결과를 읽을 때 구성 요소가 정상적으로 동작하는 방식과 테스트를 위해 수정되는 방식이 즉시 명확하지 않을 수 있습니다. -테스트 유효성: Monkeypatching은 때때로 생산 환경과 매우 다른 인위적인 조건에서 통과하는 테스트로 이어질 수 있습니다. 이렇게 하면 테스트가 시스템의 동작을 너무 크게 변경했기 때문에 테스트가 통과될 수 있으므로 보안에 대한 잘못된 인식이 생성될 수 있습니다. -구현 세부 정보에 대한 초과 의존성: monkeypatching을 사용하는 테스트는 테스트하는 코드의 특정 구현 세부 정보와 긴밀하게 결합될 수 있습니다. 이를 통해 기본 코드베이스를 약간만 변경하더라도 테스트가 취약해지고 호환성이 손상되기 쉽습니다. -디버깅 복잡성: 특히 패치가 애플리케이션 동작의 기본 측면을 변경하는 경우 monkeypatch
를 사용하는 디버깅 테스트는 더 복잡할 수 있습니다. 테스트 중에 구성 요소가 수정되는 방법에 대해 자세히 알아보기 위해 테스트가 실패하는 이유를 이해할 필요가 있을 수 있습니다.
monkeypatch
는 격리되고 제어된 테스트 환경을 만들기 위한 강력한 도구이지만 테스트 도구 모음 및 애플리케이션의 동작에 미치는 영향을 명확하게 이해하고 신중하게 사용해야 합니다.