Недавно я начал использовать 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. Однако у меня возникли проблемы с поиском четкой документации и примеров, объясняющих ключевые различия между этими двумя подходами и когда следует выбирать один из них.
Вот вопросы (для ускоренной перемотки :) ):
Основное отличие состоит в том, что с помощью 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.
Спасибо за этот ответ, это дало мне огромное понимание, которое было действительно полезно.
Основная разница не в количестве 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
.
Я нашел некоторую информацию о разнице, представленной здесь — github.com/pytest-dev/pytest/issues/2508