Skip to content

Commit bc819bc

Browse files
committed
fix target fixture registration post pytest 8.1
1 parent b542e8e commit bc819bc

File tree

2 files changed

+74
-4
lines changed

2 files changed

+74
-4
lines changed

src/pytest_bdd/compat.py

+32-4
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,41 @@ def inject_fixture(request: FixtureRequest, arg: str, value: Any) -> None:
2424
:param arg: argument name
2525
:param value: argument value
2626
"""
27-
28-
request._fixturemanager._register_fixture(
29-
name=arg,
27+
fd = FixtureDef(
28+
config=request._fixturemanager.config,
29+
baseid=request.node.nodeid,
30+
argname=arg,
3031
func=lambda: value,
31-
nodeid=request.node.nodeid,
32+
scope="function",
33+
params=None,
34+
ids=None,
35+
_ispytest=True,
3236
)
3337

38+
fd.cached_result = (value, 0, None)
39+
40+
old_fd = request._fixture_defs.get(arg)
41+
add_fixturename = arg not in request.fixturenames
42+
43+
def fin() -> None:
44+
request._fixturemanager._arg2fixturedefs[arg].remove(fd)
45+
46+
if old_fd is not None:
47+
request._fixture_defs[arg] = old_fd
48+
49+
if add_fixturename:
50+
request._pyfuncitem._fixtureinfo.names_closure.remove(arg)
51+
52+
request.addfinalizer(fin)
53+
54+
# inject fixture definition
55+
request._fixturemanager._arg2fixturedefs.setdefault(arg, []).append(fd)
56+
57+
# inject fixture value in request cache
58+
request._fixture_defs[arg] = fd
59+
if add_fixturename:
60+
request._pyfuncitem._fixtureinfo.names_closure.append(arg)
61+
3462
else:
3563

3664
def getfixturedefs(fixturemanager: FixtureManager, fixturename: str, node: Node) -> Sequence[FixtureDef] | None:

tests/steps/test_common.py

+42
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,48 @@ def _(bar, expected_value):
7878
assert bar == "test bar"
7979

8080

81+
def test_step_function_target_fixture_redefined(pytester):
82+
pytester.makefile(
83+
".feature",
84+
target_fixture=textwrap.dedent(
85+
"""\
86+
Feature: Redefine a target fixture
87+
Scenario: Redefine the target fixture after it has been injected once in the same scenario
88+
Given there is a foo with value "test foo"
89+
Then foo should be "test foo"
90+
Given there is a foo with value "test bar"
91+
Then foo should be "test bar"
92+
"""
93+
),
94+
)
95+
pytester.makepyfile(
96+
textwrap.dedent(
97+
"""\
98+
import pytest
99+
from pytest_bdd import given, when, then, scenarios, parsers
100+
from pytest_bdd.utils import dump_obj
101+
102+
scenarios("target_fixture.feature")
103+
104+
@given(parsers.parse('there is a foo with value "{value}"'), target_fixture="foo")
105+
def _(value):
106+
return value
107+
108+
@then(parsers.parse('foo should be "{expected_value}"'))
109+
def _(foo, expected_value):
110+
dump_obj(foo)
111+
assert foo == expected_value
112+
"""
113+
)
114+
)
115+
result = pytester.runpytest("-s")
116+
result.assert_outcomes(passed=1)
117+
118+
[foo1, foo2] = collect_dumped_objects(result)
119+
assert foo1 == "test foo"
120+
assert foo2 == "test bar"
121+
122+
81123
def test_step_functions_same_parser(pytester):
82124
pytester.makefile(
83125
".feature",

0 commit comments

Comments
 (0)