Python

Pytest - 2. Fixture 알아보기

r잡초처럼 2023. 2. 1. 20:19

어제에 간단하게 예제를 살펴보았다. 이번에는 Fixture의 들어가는 인수 등을 살펴보자.

1. Autouse

autouse를 True로 설정하면, 별도 요청 없이 모든 테스트 함수에서 해당 fixture를 사용할 수 있다.

 

Sometimes you may want to have a fixture (or even several) that you know all your tests will depend on. “Autouse” fixtures are a convenient way to make all tests automatically request them. This can cut out a lot of redundant requests, and can even provide more advanced fixture usage (more on that further down).

다음과 같이 쓸 수 있다.

# contents of test_append.py
import pytest


@pytest.fixture
def first_entry():
    return "a"


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


@pytest.fixture(autouse=True)
def append_first(order, first_entry):
    return order.append(first_entry)


def test_string_only(order, first_entry):
    assert order == [first_entry]


def test_string_and_int(order, first_entry):
    order.append(2)
    assert order == [first_entry, 2]

append_first를 요청하지 않아도 테스트들은 모두 이에 영향을 받는다.  

2. Scope

만약 fixture를 생성하는데 비용(시간)이 많이 걸린다면 scope 인자를 통해 fixture가 유지되는 범위를 지정할 수 있다.

예를 들어 네트워크 엑세스가 필요한 설비는 시간이 많이 걸린다. scope="module"로 설정하면 fixture가 모듈당 한 번만 호출되도록 할 수 있다.(기본값은 함수당 한 번 호출) 따라서 테스트 모듈의 여러 테스트 기능은 동일한 fixture를 사용하므로 시간이 절약된다. 

다음 예제를 살펴보자.

# content of conftest.py
import smtplib

import pytest


@pytest.fixture(scope="module")
def smtp_connection():
    return smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
# content of test_module.py


def test_ehlo(smtp_connection):
    response, msg = smtp_connection.ehlo()
    assert response == 250
    assert b"smtp.gmail.com" in msg
    assert 0  # for demo purposes


def test_noop(smtp_connection):
    response, msg = smtp_connection.noop()
    assert response == 250
    assert 0  # for demo purposes

여기서 test_ehlo에는 smtp_connection 고정장치 값이 필요하다. pytest가 @pytest를 발견하고 호출한다. smtp_connection fixture 함수로 표시된 테스트를 실행하는 방법은 다음과 같다.

$ pytest test_module.py
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
collected 2 items

test_module.py FF                                                    [100%]

================================= FAILURES =================================
________________________________ test_ehlo _________________________________

smtp_connection = <smtplib.SMTP object at 0xdeadbeef0001>

    def test_ehlo(smtp_connection):
        response, msg = smtp_connection.ehlo()
        assert response == 250
        assert b"smtp.gmail.com" in msg
>       assert 0  # for demo purposes
E       assert 0

test_module.py:7: AssertionError
________________________________ test_noop _________________________________

smtp_connection = <smtplib.SMTP object at 0xdeadbeef0001>

    def test_noop(smtp_connection):
        response, msg = smtp_connection.noop()
        assert response == 250
>       assert 0  # for demo purposes
E       assert 0

test_module.py:13: AssertionError
========================= short test summary info ==========================
FAILED test_module.py::test_ehlo - assert 0
FAILED test_module.py::test_noop - assert 0
============================ 2 failed in 0.12s =============================

해당 오류를 보면 동일한 인스턴스가 두 테스트 코드에 전달되었음을 확인 할 수 있다. 동일한 인스턴스를 재사용하기 때문에 단일 인스턴스만큼 빠르게 실행된다.

2.1 scope의 범위

Fixtures are created when first requested by a test, and are destroyed based on their scope:

  • function: 기본 scope이다. 테스트 종료 시 파괴 된다.
  • class: 클래스의 마지막 테스트를 해체하는 동안 파괴된다.
  • module: 모듈의 마지막 테스트를 해체하는 동안 파괴된다.
  • package: 패키지 범위
  • session: 세션 범위

2.2 동적 스코프

fixture name을 문자열로 설정하고 구성 객체로 구성하는 두 개의 키워드 인수로 호출된다. 이것은 도커 컨테이너를 생성하는 것과 같이 설치 시간이 필요한 설비를 처리할 때 특히 유용할 수 있다. 명령행 인수를 사용하여 다른 환경에 대해 생성된 컨테이너의 범위를 제어할 수 있다.(이 부분은 다음에 좀 더 자세히 살펴보겠다.)

def determine_scope(fixture_name, config):
    if config.getoption("--keep-containers", None):
        return "session"
    return "function"


@pytest.fixture(scope=determine_scope)
def docker_container():
    yield spawn_container()

참고

https://docs.pytest.org/en/latest/how-to/fixtures.html#yield-fixtures-recommended

 

How to use fixtures — pytest documentation

Scope: sharing fixtures across classes, modules, packages or session Fixtures requiring network access depend on connectivity and are usually time-expensive to create. Extending the previous example, we can add a scope="module" parameter to the @pytest.fix

docs.pytest.org

https://velog.io/@sangyeon217/pytest-fixture#scope-%EC%84%A4%EC%A0%95

 

Pytest Fixture 생성

Pytest Fixture 에 대한 포스팅 입니다.

velog.io