diff --git a/changelog/7061.bugfix.rst b/changelog/7061.bugfix.rst new file mode 100644 index 000000000..7e6d36c2f --- /dev/null +++ b/changelog/7061.bugfix.rst @@ -0,0 +1 @@ +When a yielding fixture fails to yield a value, report a test setup error instead of crashing. diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index f9e0f3b28..f98be8278 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -786,13 +786,18 @@ def fail_fixturefunc(fixturefunc, msg): def call_fixture_func(fixturefunc, request, kwargs): yieldctx = is_generator(fixturefunc) if yieldctx: - it = fixturefunc(**kwargs) - res = next(it) - finalizer = functools.partial(_teardown_yield_fixture, fixturefunc, it) + generator = fixturefunc(**kwargs) + try: + fixture_result = next(generator) + except StopIteration: + raise ValueError( + "{} did not yield a value".format(request.fixturename) + ) from None + finalizer = functools.partial(_teardown_yield_fixture, fixturefunc, generator) request.addfinalizer(finalizer) else: - res = fixturefunc(**kwargs) - return res + fixture_result = fixturefunc(**kwargs) + return fixture_result def _teardown_yield_fixture(fixturefunc, it): diff --git a/testing/python/fixtures.py b/testing/python/fixtures.py index 36e55a0e1..8cce3ebde 100644 --- a/testing/python/fixtures.py +++ b/testing/python/fixtures.py @@ -3,6 +3,7 @@ import textwrap import pytest from _pytest import fixtures +from _pytest.config import ExitCode from _pytest.fixtures import FixtureRequest from _pytest.pathlib import Path from _pytest.pytester import get_public_names @@ -4290,3 +4291,23 @@ def test_fixture_arg_ordering(testdir): ) result = testdir.runpytest("-vv", str(p1)) assert result.ret == 0 + + +def test_yield_fixture_with_no_value(testdir): + testdir.makepyfile( + """ + import pytest + @pytest.fixture(name='custom') + def empty_yield(): + if False: + yield + + def test_fixt(custom): + pass + """ + ) + expected = "E ValueError: custom did not yield a value" + result = testdir.runpytest() + result.assert_outcomes(error=1) + result.stdout.fnmatch_lines([expected]) + assert result.ret == ExitCode.TESTS_FAILED