pytest 플러그인 직접 작성하기

pytest 플러그인 직접 작성하기

pytest의 확장 포인트는 훅(hook) 이에요. 설정, 수집, 실행, 리포트의 모든 단계가 잘 정의된 훅 호출로 이뤄져서, 여기에 내 함수를 등록하는 것만으로도 플러그인이 돼요. 작은 프로젝트에서는 conftest.py라는 로컬 플러그인으로 시작하고, 여러 프로젝트에서 쓰려면 pip로 설치 가능한 플러그인으로 포장할 수 있어요. 여기서는 로컬 conftest.py 플러그인부터 pyproject.tomlpytest11 엔트리포인트로 배포하는 방법, 그리고 pytester로 플러그인을 테스트하는 방법까지 살펴볼게요.

출처: pytest 공식 문서 - Writing plugins

훅과 플러그인의 구조

플러그인은 하나 이상의 훅 함수를 담아요. pytest는 설정·수집·실행·리포트의 모든 측면을 다음 세 종류의 플러그인이 제공하는 훅 호출로 구현해요.

  • 내장 플러그인 — pytest의 내부 _pytest 디렉토리에서 로드
  • 외부 플러그인 — 패키징 메타데이터의 엔트리포인트로 발견되는, 설치된 서드파티 모듈
  • conftest.py 플러그인 — 테스트 디렉토리에서 자동 발견되는 모듈

원칙적으로 각 훅 호출은 1:N 파이썬 함수 호출이에요. 여기서 N은 주어진 스펙에 대해 등록된 구현 함수의 개수예요. 모든 스펙과 구현은 pytest_ 접두사 규칙을 따르므로 구분하고 찾기가 쉬워요.

conftest.py: 디렉토리별 로컬 플러그인

로컬 conftest.py 플러그인은 디렉토리별 훅 구현을 담아요. 테스트 실행은 파일시스템 루트에 더 가까운 conftest.py에 정의된 훅을 모두 호출해요.

예를 들어 a 하위 디렉토리의 테스트에서만 호출되는 pytest_runtest_setup 훅을 구현한다면, a/conftest.py에 훅을 정의하면 돼요.

# a/conftest.py
def pytest_runtest_setup(item):
    # called for running each test in 'a' directory
    print("setting up", item)

이 상태에서 pytest test_flat.py --capture=no는 "setting up"을 출력하지 않고, pytest a/test_sub.py --capture=no는 출력해요. 다만 일부 훅은 pytest가 시작 시 플러그인을 발견하는 방식 때문에 초기(initial)가 아닌 conftest.py에서는 구현할 수 없어요. 각 훅 문서에서 제약을 확인해야 해요.

pyproject.toml로 배포 가능한 플러그인 만들기

플러그인을 다른 프로젝트에서도 쓰도록 배포하려면, 엔트리포인트를 정의해서 pytest가 플러그인 모듈을 찾게 만들면 돼요. pytest는 pytest11 엔트리포인트를 조회해서 플러그인을 발견하므로, pyproject.toml에 정의할 수 있어요.

# sample ./pyproject.toml file
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "myproject"
classifiers = [
    "Framework :: Pytest",
]

[project.entry-points.pytest11]
myproject = "myproject.pluginmodule"

이렇게 설치된 패키지는 myproject.pluginmodule을 플러그인으로 로드하고, 그 안에서 훅을 정의할 수 있어요. 등록 확인은 pytest --trace-config로 할 수 있어요. 사용자들이 찾기 쉽도록 PyPI classifiers에 Framework :: Pytest를 꼭 넣는 것도 잊지 마세요.

pytest_plugins로 플러그인 요청하기

테스트 모듈이나 conftest.py에서 pytest_plugins 변수로 플러그인을 요청할 수 있어요. pytest_plugins로 가져온 플러그인은 자동으로 assertion rewriting 대상이 되기도 해요.

pytest_plugins = ["name1", "name2"]

플러그인을 테스트할 때는 이 메커니즘이 자주 쓰여요. 다만 루트가 아닌 conftest.py에서 pytest_plugins를 쓰는 건 권장하지 않아요(이제는 deprecated).

pytester로 플러그인 테스트하기

pytest에는 플러그인 코드를 테스트하는 데 도움을 주는 pytester 플러그인이 내장되어 있어요. 기본적으로 비활성화되어 있으므로, 테스트 디렉토리의 conftest.py에 아래 줄을 추가하거나 -p pytester 옵션으로 켜야 해요.

# content of conftest.py
pytest_plugins = ["pytester"]
pytest -p pytester

이러면 pytester 픽스처를 사용할 수 있어서, 테스트 안에서 임시 테스트 파일을 만들어 플러그인 동작을 검증할 수 있어요.

더 알아보기 (Learn more)