pytest-dev / pytest

The pytest framework makes it easy to write small tests, yet scales to support complex functional testing
https://pytest.org
MIT License
11.93k stars 2.65k forks source link

expose `fixture.manual` as context-manager for yield fixtures #12823

Open RonnyPfannschmidt opened 2 weeks ago

RonnyPfannschmidt commented 2 weeks ago

What's the problem this feature will solve?

unlike normal context managers, fixtures functions cannot easily be used in a manual way as a contextmanager

Describe the solution you'd like

# typed in untested in web form - slightly pathological example
@fixture
def manager():
    yield SomeResourceManager()

@fixture
def managed_resource(manager, login_data):
   with manager.client(login_data) as client:
     yield client

def test_happy(managed_resource):
    assert managed_resouce.interact() == "happy"

def test_failed_login_triggers_xfail(manager):
   with pytest.raises(pytest.xfail):
        with managed_resource.manual(manager, {"bad": "login"}):
          pass

Alternative Solutions

wrapping a fixtures function into contextmanager as api makes for a ugly api

hacked_cm = contextlib.contextmanager(managed_resource.__pytest_wrapped__.obj)
nicoddemus commented 2 weeks ago

I understand the rationale, but in those cases I think a reasonable workaround is to refactor the fixture code into a contextmanager, and use that in the fixture:

@contextmanager
def managed_resource(manager, login_data): 
   with manager.client(login_data) as client:
     yield client

@fixture(name="managed_resource")
def managed_resource_fixture(manager, login_data):
   with my_managed_resource(manager, login_data):
     yield client

Not sure we need to add this to the pytest core, given this is not common occurrence (at least in my experience).

My 2 cents