Выбор между выходом и addfinalizer в pytest. Исправления для демонтажа

Недавно я начал использовать pytest для тестирования на Python и создал приспособление для управления коллекцией элементов с помощью gRPC. Ниже приведен фрагмент кода моего прибора:

import pytest

@pytest.fixture(scope = "session")
def collection():
    grpc_page = GrpcPages().collections

    def create_collection(collection_id=None, **kwargs):
        default_params = {
            "id": collection_id,
            "is_active": True,
            # some other params
        }
        try:
            return grpc_page.create_collection(**{**default_params, **kwargs})
        except Exception as err:
            print(err)
            raise err

    yield create_collection

    def delete_created_collection():
        # Some code to hard and soft delete created data

Это моя первая попытка создания прибора, и я понял, что мне нужен механизм для удаления данных, созданных в течение жизненного цикла прибора.

Изучая варианты реализации процедур демонтажа, я наткнулся на выходные данные и addfinalizer. Насколько я понимаю, оба можно использовать для определения действий по удалению в приспособлениях pytest. Однако у меня возникли проблемы с поиском четкой документации и примеров, объясняющих ключевые различия между этими двумя подходами и когда следует выбирать один из них.

Вот вопросы (для ускоренной перемотки :) ):

  1. Каковы основные различия между использованием доходности и addfinalizer в приспособлениях pytest для обработки демонтажа?
  2. Существуют ли конкретные сценарии, в которых один предпочтительнее другого?

Я нашел некоторую информацию о разнице, представленной здесь — github.com/pytest-dev/pytest/issues/2508

llRub3Nll 09.07.2024 19:45
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
1
72
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Основное отличие состоит в том, что с помощью addfinalizer вы можете добавить столько финализаторов, сколько вам нужно, что полезно в сложных сценариях демонтажа.

Если настройка и демонтаж просты, нет необходимости использовать addfinalizer:

@pytest.fixture
def resource():
    resource = create_resource()
    yield resource
    resource.cleanup()

Но если вам нужно, например. несколько шагов очистки, addfinalizer позволяет сделать это более понятным способом:

@pytest.fixture
def resource(request):
    resource = create_resource()
    request.addfinalizer(resource.cleanup)
    request.addfinalizer(resource.log)
    ...
    return resource

Просто как тот :)

Это действительно хороший и обоснованный момент, я этого не заметил. В этом есть смысл. Но нет ли каких-либо других отличий, например, что делает yield, когда вы используете его как оператор возврата, как в случае с addfinilizer вам нужно отдельно возвращать то, что вам нужно, чего не происходит с выходом. Мне бы хотелось узнать больше о том, что происходит под капотом, когда я использую выход и addfinilizer.

llRub3Nll 09.07.2024 06:57

Спасибо за этот ответ, это дало мне огромное понимание, которое было действительно полезно.

llRub3Nll 09.07.2024 06:57
Ответ принят как подходящий

Основная разница не в количестве addfinalizer или fixture, разницы вообще нет. Вы можете добавить столько, сколько захотите (или просто иметь более одной операции над ними)

@pytest.fixture(scope='session', autouse=True)
def fixture_one():
    print('fixture_one setup')
    yield
    print('fixture_one teardown')


@pytest.fixture(scope='session', autouse=True)
def fixture_two():
    print('fixture_two setup')
    yield
    print('fixture_two teardown')


def test_one():
    print('test_one')

Выход

example.py::test_one 
fixture_one setup
fixture_two setup
PASSED                                    [100%]test_one
fixture_two teardown
fixture_one teardown

Основное различие заключается в том, будет ли выполняться демонтаж в случае сбоя на этапе настройки. Это полезно, если необходимо выполнить очистку, даже если установка не удалась.

Без финализатора демонтаж не запустится, если в настройке было исключение.

@pytest.fixture(scope='session', autouse=True)
def fixture_one():
    print('fixture_one setup')
    raise Exception('Error')
    yield
    print('fixture_one teardown')


def test_one():
    print('test_one')

Выход

ERROR                                     [100%]
fixture_one setup

test setup failed
...
E       Exception: Error

example.py:8: Exception

Но с финализатором это будет

@pytest.fixture(scope='session', autouse=True)
def fixture_one(request):
    def finalizer():
        print('fixture_one teardown')

    request.addfinalizer(finalizer)
    print('fixture_one setup')
    raise Exception('Error')
    yield

Выход

ERROR                                     [100%]
fixture_one setup

test setup failed
...
E       Exception: Error

example.py:13: Exception
fixture_one teardown

Это блестящий ответ, спасибо, который многое меняет. Я думаю, что в некоторых случаях в моем случае меня не волнует демонтаж, а в некоторых случаях мне нужно демонтаж, даже если установка не удалась, поэтому я буду использовать смесь того и другого, или, как вы упомянули, различий нет, возможно, я буду использовать только addfinilizer.

llRub3Nll 09.07.2024 08:34

Другие вопросы по теме