[pytest-dev] solving the "too static" fixture scope problem
holger krekel
holger at merlinux.eu
Fri Oct 11 10:40:45 CEST 2013
Hi pytest users and developers,
I'd like to discuss and get feedback on
extending the fixture mechanism and fix what
i consider a biggest limitation at the moment.
Problem: fixtures are tied statically to a scope
=================================================
For example, you cannot use monkeypatch in a higher
than "function" scoped fixture. Same is true for
tmpdir and probably also many user-defined fixtures.
I've certainly had this problem myself many times
that i had a fixture function that didn't really
care in what scope it was used. There are
ways to get around this problem but they are not
pretty:
@pytest.fixture(scope="module")
def myfix_module(request
return _myfix(request)
@pytest.fixture(scope="function")
def myfix_function(request
return _myfix(request)
where _myfix is the function that doesn't
care about the actual scope. Even then, you
can't use builtin fixtures like "monkeypatch",
"tmpdir", etc.
Solution Idea: introduce "each" scoped fixtures
=====================================================
The idea is allow a fixture function to declare it wants
to be used in the scope of the requesting fixture function
(or at function-scope if used from a test).
This is how "monkeypatch" would be implemented then:
@pytest.fixture(scope="each")
def monkeypatch(request):
... # same implementation as in _pytest/monkeypatch.py
The new "each" scope means that each fixture/test requesting
the "monkeypatch" fixture would receive its own fixture instance.
So a session-scoped fixture could naturally use it like this:
@pytest.fixture(scope="session")
def myfix(monkeypatch):
monkeypatch.setattr(...)
return some_value
The passed in monkeypatch object here is a specific instance just
for the ``myfix`` fixture function: "each" fixture function
requesting ``monkeypatch`` gets a new instance of it.
If e.g. a test uses another module-scoped fixture defined like this:
@pytest.fixture(scope="module")
def myfix2(monkeypatch):
mp.setattr(...)
return some_value
this would invoke the ``monkeypatch`` fixture function a second time,
resulting in a new instance for use by the ``myfix2`` instance.
The same logic could be applied to other fixtures
like "tmpdir" or user-defined ones.
Do you like this idea? Would you find it helpful for your test suites?
There is one issue i am not sure about yet, however. Currently,
when a test requires fixture A and B, and B requires C and C requires A,
then the two "A" would be exactly the same object, independently of what
which scopes are declared. If A=="tmpdir", then the test's tmpdir and
C's tmpdir would be the same directory. I often don't find this desirable.
If tmpdir would be an "each" scoped fixture, then C and the test would
each receive a clean new tmpdir. If that is a backward-compat issue,
we could introduce another name for the new "each" scoped tmpdir.
I usually find myself working around the problem of a "tmpdir"
shared by multiple different fixtures, though.
cheers,
holger
More information about the Pytest-dev
mailing list