pytest-dev / pytest-bdd

BDD library for the py.test runner
https://pytest-bdd.readthedocs.io/en/latest/
MIT License
1.3k stars 219 forks source link

Custom fixture unable to inherit target_fixtures #695

Closed AmirYa412 closed 1 week ago

AmirYa412 commented 2 months ago

I am trying to create a custom fixture based on value created from a step's target_fixture with no success. I do understand custom and target_fixture are not exactly the same, but I wonder if there is a way I can make it work. For example:

# My custom fixture
@pytest.fixture
def storyboard(storyboard_response):
    return storyboard_response["storyboard"]

@when("get storyboard", target_fixture="storyboard_response")
def get_timeline_storyboard(driver, request):
    response = driver.get_storyboard(123)
    return response

When I try to use a another step that inherit storyboard custom fixture, I get this error:

venv-e2e/lib/python3.7/site-packages/pytest_bdd/scenario.py:216 (test_render_timeline_storyboard_with_video_sources)
.0 = <list_iterator object at 0x7f8b0835aeb8>

>   kwargs = {arg: kwargs[arg] if arg in kwargs else request.getfixturevalue(arg) for arg in args}

venv-e2e/lib/python3.7/site-packages/pytest_bdd/scenario.py:154: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
venv-e2e/lib/python3.7/site-packages/_pytest/fixtures.py:585: in getfixturevalue
    fixturedef = self._get_active_fixturedef(argname)
venv-e2e/lib/python3.7/site-packages/_pytest/fixtures.py:607: in _get_active_fixturedef
    self._compute_fixture_value(fixturedef)
venv-e2e/lib/python3.7/site-packages/_pytest/fixtures.py:693: in _compute_fixture_value
    fixturedef.execute(request=subrequest)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <FixtureDef argname='storyboard' scope='function' baseid=''>
request = <SubRequest 'storyboard' for <Function test_render_timeline_storyboard_with_video_sources>>

    def execute(self, request: SubRequest) -> FixtureValue:
        # Get required arguments and register our own finish()
        # with their finalization.
        for argname in self.argnames:
            fixturedef = request._get_active_fixturedef(argname)
            if argname != "request":
                # PseudoFixtureDef is only for "request".
>               assert isinstance(fixturedef, FixtureDef)
E               AssertionError

venv-e2e/lib/python3.7/site-packages/_pytest/fixtures.py:1048: AssertionError

As workaround that I prefer not to do, I defined the storyboard in conftest.py and I retrieve the target_fixture value like this:

@pytest.fixture
def storyboard(request):
    # Storyboard custom fixture for easier access
    storyboard_response = request.getfixturevalue("storyboard_response")
    return storyboard_response["storyboard"]
youtux commented 1 week ago

yes that's the only way, as we inject fixtures only when the step is executed, so it's just not possible to access its value before the step is executed