diff --git a/changelog/2909.bugfix.rst b/changelog/2909.bugfix.rst new file mode 100644 index 000000000..534d17490 --- /dev/null +++ b/changelog/2909.bugfix.rst @@ -0,0 +1 @@ +Improve error message when a recursive dependency between fixtures is detected. diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 29eda351f..cfc187bc2 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -762,14 +762,19 @@ class FixtureLookupError(LookupError): if msg is None: fm = self.request._fixturemanager - available = [] + available = set() parentid = self.request._pyfuncitem.parent.nodeid for name, fixturedefs in fm._arg2fixturedefs.items(): faclist = list(fm._matchfactories(fixturedefs, parentid)) - if faclist and name not in available: - available.append(name) - msg = "fixture %r not found" % (self.argname,) - msg += "\n available fixtures: %s" % (", ".join(sorted(available)),) + if faclist: + available.add(name) + if self.argname in available: + msg = " recursive dependency involving fixture '{}' detected".format( + self.argname + ) + else: + msg = "fixture '{}' not found".format(self.argname) + msg += "\n available fixtures: {}".format(", ".join(sorted(available))) msg += "\n use 'pytest --fixtures [testpath]' for help on them." return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname) diff --git a/testing/example_scripts/fixtures/fill_fixtures/test_detect_recursive_dependency_error.py b/testing/example_scripts/fixtures/fill_fixtures/test_detect_recursive_dependency_error.py new file mode 100644 index 000000000..d1efcbb33 --- /dev/null +++ b/testing/example_scripts/fixtures/fill_fixtures/test_detect_recursive_dependency_error.py @@ -0,0 +1,15 @@ +import pytest + + +@pytest.fixture +def fix1(fix2): + return 1 + + +@pytest.fixture +def fix2(fix1): + return 1 + + +def test(fix1): + pass diff --git a/testing/python/fixture.py b/testing/python/fixture.py index f21f7a861..02304ac32 100644 --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -60,6 +60,13 @@ class TestFillFixtures(object): """ ) + def test_detect_recursive_dependency_error(self, testdir): + testdir.copy_example() + result = testdir.runpytest() + result.stdout.fnmatch_lines( + ["*recursive dependency involving fixture 'fix1' detected*"] + ) + def test_funcarg_basic(self, testdir): testdir.copy_example() item = testdir.getitem(Path("test_funcarg_basic.py"))