pytest 명령줄에서 테스트 실행하고 선별하기

pytest 명령줄에서 테스트 실행하고 선별하기

테스트는 일반적으로 명령줄에서 pytest를 실행해 돌려요. 현재 디렉터리와 하위 디렉터리에서 test_*.py*_test.py 형식의 이름을 가진 파일들의 테스트를 모두 실행합니다. 여기서는 어떤 테스트를 골라 실행하는지, 플러그인 로딩을 어떻게 조절하는지 등 명령줄 사용법을 살펴볼게요.

출처: How to invoke pytest — pytest 공식 문서

본문

실행할 테스트 지정하기

pytest는 명령줄이나 파일에서 테스트를 실행·선별하는 여러 방법을 지원해요.

모듈의 테스트 실행

pytest test_mod.py

디렉터리의 테스트 실행

pytest testing/

키워드 표현식으로 테스트 실행

pytest -k 'MyClass and not method'

이러면 주어진 문자열 표현식(대소문자 무시)과 이름이 매칭되는 테스트를 실행해요. 표현식은 파일명·클래스명·함수명을 변수로 쓰는 파이썬 연산자를 쓸 수 있어요. 위 예는 TestMyClass.test_something은 실행하되 TestMyClass.test_method_simple은 실행하지 않습니다. Windows에서 실행할 때는 표현식에 '' 대신 ""를 쓰세요.

수집 인자로 테스트 실행

모듈 파일명을 작업 디렉터리 기준 상대 경로로 넘기되, 클래스명·함수명 같은 지정자는 ::로 구분하고, 파라미터화된 인자는 []로 감쌉니다.

모듈 안의 특정 테스트 실행:

pytest tests/test_mod.py::test_func

클래스의 모든 테스트 실행:

pytest tests/test_mod.py::TestClass

특정 테스트 메서드 지정:

pytest tests/test_mod.py::TestClass::test_method

특정 파라미터화 실행:

pytest tests/test_mod.py::test_func[x1,y2]

마커 표현식으로 테스트 실행

@pytest.mark.slow 데코레이터가 붙은 모든 테스트 실행:

pytest -m slow

phase 키워드 인자가 1로 설정된 주석형 @pytest.mark.slow(phase=1) 데코레이터가 붙은 모든 테스트 실행:

pytest -m "slow(phase=1)"

자세한 내용은 마크 문서를 참고하세요.

패키지에서 테스트 실행

pytest --pyargs pkg.testing

이러면 pkg.testing을 import해서 그 파일시스템 위치로 테스트를 찾아 실행합니다.

파일에서 인자 읽기

다음은 버전 8.2에서 추가된 기능이에요. 위의 모든 인자는 @ 접두사로 파일에서 읽을 수 있습니다.

pytest @tests_to_run.txt

tests_to_run.txt는 한 줄에 항목 하나씩 담아요. 예:

tests/test_file.py
tests/test_mod.py::test_func[x1,y2]
tests/test_mod.py::TestClass
-m slow

이 파일은 pytest --collect-only -q로 생성한 뒤 필요에 따라 수정할 수도 있습니다.

버전·옵션·환경변수 도움말 보기

pytest --version   # shows where pytest was imported from
pytest --fixtures  # show available builtin function arguments
pytest -h | --help # show help on command line and config file options

테스트 실행 시간 프로파일링

1.0초 이상 걸리는 가장 느린 10개 테스트 목록을 보려면:

pytest --durations=10 --durations-min=1.0

기본적으로 pytest는 명령줄에 -vv를 넘기지 않으면 너무 짧은(<0.005초) 테스트 시간은 보여주지 않아요.

플러그인 로딩 관리

플러그인 일찍 로딩하기

명령줄에서 -p 옵션으로 내부·외부 플러그인을 명시적으로 일찍 로딩할 수 있습니다.

pytest -p mypluginmodule

이 옵션은 name 인자를 받는데, 여기에는 두 가지를 쓸 수 있어요.

  • myproject.plugins같은 import 가능한 전체 모듈 점(dotted) 이름
  • 플러그인의 엔트리포인트 이름. 플러그인 등록 시 importlib에 넘겨지는 이름이에요. 예를 들어 pytest-cov 플러그인을 일찍 로딩하려면 다음과 같이 합니다.
pytest -p pytest_cov

플러그인 비활성화하기

호출 시점에 특정 플러그인 로딩을 끄려면 -p 옵션에 no: 접두사를 붙이면 돼요. 텍스트 파일의 doctest 테스트를 실행하는 데 쓰이는 doctest 플러그인을 끄는 예시:

pytest -p no:doctest

pytest를 호출하는 다른 방법

python -m pytest로 호출하기

명령줄에서 파이썬 인터프리터를 통해 테스트를 호출할 수 있어요.

python -m pytest [...]

이것은 명령줄 스크립트 pytest [...]를 직접 호출하는 것과 거의 동일하지만, python으로 호출하면 현재 디렉터리를 sys.path에 추가한다는 차이가 있어요.

파이썬 코드에서 pytest 호출하기

파이썬 코드에서 pytest를 직접 호출할 수 있습니다.

retcode = pytest.main()

명령줄에서 pytest를 호출하는 것과 같은 동작을 해요. SystemExit를 일으키지 않고 exit code를 반환합니다. 인자를 넘기지 않으면 main은 프로세스의 명령줄 인자(sys.argv)에서 읽어오는데, 이건 바람직하지 않을 수 있어요. 옵션과 인자를 명시적으로 넘길 수 있습니다.

retcode = pytest.main(["-x", "mytestdir"])

pytest.main에 추가 플러그인을 지정할 수도 있어요.

# content of myinvoke.py
import sys

import pytest


class MyPlugin:
    def pytest_sessionfinish(self):
        print("*** test run reporting finishing")


if __name__ == "__main__":
    sys.exit(pytest.main(["-qq"], plugins=[MyPlugin()]))

실행하면 MyPlugin이 추가됐고 그 훅이 호출됐다는 것이 보여요.

$ python myinvoke.py
*** test run reporting finishing

참고로 pytest.main()을 호출하면 테스트와 그것이 import하는 모듈들을 import하게 돼요. 파이썬 import 시스템의 캐싱 메커니즘 때문에, 같은 프로세스에서 pytest.main()을 연달아 호출하면 그 사이에 파일이 바뀌어도 반영되지 않습니다. 따라서 같은 프로세스에서 pytest.main()을 여러 번 호출(예: 테스트 재실행)하는 것은 권장하지 않아요.

더 알아보기