diff --git a/changelog/4497.bugfix.rst b/changelog/4497.bugfix.rst new file mode 100644 index 00000000000..ff071d4cec9 --- /dev/null +++ b/changelog/4497.bugfix.rst @@ -0,0 +1 @@ +Fixed crash when running an empty ``xfail``-marked parameter set with ``--runxfail``; it now fails with a clear message. diff --git a/src/_pytest/python.py b/src/_pytest/python.py index bc3d55243f7..304b9d512ab 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -1228,7 +1228,12 @@ def id(self) -> str: def get_direct_param_fixture_func(request: FixtureRequest) -> Any: - return request.param + try: + return request.param + except AttributeError: + # Empty parameter set under --runxfail has no value to run with: + # fail cleanly instead of crashing (#4497). + fail("no direct parameter (empty parameter set)") class DirectParamFixtureDef(FixtureDef[FixtureValue]): diff --git a/testing/test_skipping.py b/testing/test_skipping.py index fbe196915e8..fa7a72db88c 100644 --- a/testing/test_skipping.py +++ b/testing/test_skipping.py @@ -545,6 +545,25 @@ def test_this(): """ ) + def test_runxfail_with_empty_parameter_set_mark_xfail( + self, pytester: Pytester + ) -> None: + """--runxfail on an empty xfail set fails cleanly, not crashes (#4497).""" + p = pytester.makepyfile( + """ + import pytest + + @pytest.mark.parametrize(("a", "b"), ()) + def test(a, b): + pass + """ + ) + result = pytester.runpytest( + p, "--runxfail", "-o", "empty_parameter_set_mark=xfail" + ) + result.stdout.fnmatch_lines(["*no direct parameter (empty parameter set)*"]) + result.assert_outcomes(errors=1) + def xtest_dynamic_xfail_set_during_setup(self, pytester: Pytester) -> None: p = pytester.makepyfile( """