conftest.py on Pytest

Dahun Yoo·2023년 11월 26일
0

Introduce to Pytest

목록 보기
6/7
post-thumbnail

이번 포스트에서는 Pytest에서 사용되는 conftest.py 라는 이름을 가진 파일에 대해 기재해봅니다.

conftest.py

conftest.py: sharing fixtures across multiple files

The conftest.py file serves as a means of providing fixtures for an entire directory. Fixtures defined in a conftest.py can be used by any test in that package without needing to import them (pytest will automatically discover them).

You can have multiple nested directories/packages containing your tests, and each directory can have its own conftest.py with its own fixtures, adding on to the ones provided by the conftest.py files in parent directories.

Pytest 프레임워크를 사용할 때, conftest.py 라는 이름을 가진 파일을 만든다면, 이 파일은 fixturehook 이라는 기능을 이용해 모든 테스트파일에 특정 기능 혹은 특정 값을 공유/적용할 수 있게 됩니다.

더군다나 conftest.py 라는 이름의 파일을 pytest가 자동으로 인식을 해주기 때문에, 실제 fixture기능을 호출해야하는 테스트파일들에서, 별도의 import 문을 기재하지 않아도 자동으로 사용할 수 있게 됩니다.

또한 테스트파일들이 여러 중첩된 디렉토리 하위에 존재하고 있다면, 해당 디렉토리들에 각각의 conftest.py를 작성하여, 해당 디렉토리에 대한 scope로만 동작하는 fixture, hook들을 구성해줄 수도 있고, 동일한 이름의 fixture에 대해 over-ride도 가능합니다.

Fixture

공식문서의 예시를 예로 들어 좀 더 설명해보자면 아래와 같습니다.

tests/
    __init__.py

    conftest.py
        # content of tests/conftest.py
        import pytest

        @pytest.fixture
        def order():
            return []

        @pytest.fixture
        def top(order, innermost):
            order.append("top")

    test_top.py
        # content of tests/test_top.py
        import pytest

        @pytest.fixture
        def innermost(order):
            order.append("innermost top")

        def test_order(order, top):
            assert order == ["innermost top", "top"]

    subpackage/
        __init__.py

        conftest.py
            # content of tests/subpackage/conftest.py
            import pytest

            @pytest.fixture
            def mid(order):
                order.append("mid subpackage")

        test_subpackage.py
            # content of tests/subpackage/test_subpackage.py
            import pytest

            @pytest.fixture
            def innermost(order, mid):
                order.append("innermost subpackage")

            def test_order(order, top):
                assert order == ["mid subpackage", "innermost subpackage", "top"]

위 코드에서 conftest.py의 fixture를 불러와 실해앟는 테스트 코드는 아래 2가지 입니다.

  • tests/test_top.py
  • tests/subpackage/test_subpackage.py

test_top.pytest_order()의 fixture 실행 순서를 확인하자면 아래와 같을 것 입니다.

  • test_order()에서 fixtrue ordertop을 호출합니다.
  • test/conftest.py에서 order가 호출되어 빈 배열을 리턴합니다.
  • test/conftest.pytop()에서 다시 같은 레벨에 위치한 fixture목록죽에 innermost() fixtrue를 호출합니다.
  • test/test_top.py 내부에 있던 innermost() fixture는 배열에 innermost top 문자열을 append 합니다.
  • 실행이 끝나고 다시 top() fixture로 돌아와 문자열 top을 append 합니다.
  • fixture들의 최종실행이 종료된 후에, 배열 order에는 2개의 문자열요소, "innermost top", "top" 가 존재하게 됩니다.

다음으로 test_subpackage.py 의 fixture 실행 순서를 확인하자면 아래와 같을 것 입니다.

  • test_order()에서 fixture ordertop이 호출됩니다.
  • test/conftest.py에 위치해있는 conftest.py에서 order fixture의 실행 결과로 빈 배열을 리턴합니다.
  • test/conftest.py에 위치해 있는 top fixture에서 다시 innermost fixture를 호출합니다. 이 때 호출되는 innermost는 실제로 테스트가 호출된 subpackage/test_subpackage.pyinnermost가 우선적으로 호출됩니다. (같은 계층)
  • tests/subpackage/test_subpackage.py 내부의 innermost fixture는 다시 같은 계층(tests/subpackage)의 conftest.py 내부에 있는 mid fixture를 호출합니다.
  • mid fixture는 order 배열에 mid subpackage 내용의 문자열을 append합니다.
  • tests/subpackage/test_subpackage.pyinnermost에서 innermost subpackage 문자열을 append합니다.
  • test/conftest.py 로 올라와 top fixture에서 top 문자열을 append합니다.

위 예시의 코드의 흐름에서처럼, conftest.py 는 test파일들에게 특정기능들을 제공해주는 역할을 하며 scope에 따라 기존 fixture를 overriding할 수 있습니다.

hook

hook 역시 대부분의 경우 conftest.py에 작성되며, 몇몇 hook의 경우 pytest가 hook을 실행하는 로직으로 인하여 반드시 루트디렉토리에 위치한 conftest.py에 기재되어야 합니다.

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

a/test_sub.py:
    def test_sub():
        pass

test_flat.py:
    def test_flat():
        pass

pytest test_flat.py --capture=no  # will not show "setting up"
pytest a/test_sub.py --capture=no  # will show "setting up"

hook 역시 conftest.py의 위치로 인하여 오버라이딩이 가능하거나, 스코프 범위 밖에서는 호출할 수가 없습니다.

conftest.py의 주의점

모든 테스트에서 사용되는 fixture들에 대해 하나의 conftest.py (특히 루트 디렉토리에 존재하는 프로젝트 전체를 통틀어 딱 하나의 conftest.py 파일만 존재하는 경우) 내에 선언할 경우, pytest의 초기 실행이 많이 느려질 수 있습니다. 그렇기 때문에 테스트파일들에 대해 적절히 디렉토리 별 성격을 구분하여 테스트파일들을 분류하고, 각각의 디렉토리 별로 conftest.py 파일을 만들어서 fixture관리를 하는 것이, 전체적인 pytest 프레임워크의 시간을 줄일 뿐더러, override를 통해 모든 fixture에 대해 유니크한 이름을 지어주지 않아도 되는 장점이 있습니다.

끝!

ref

profile
QA Engineer

0개의 댓글