-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Description
I'm not sure whether this is a bug. I have a fixture which automatically cleans up resources that are expensive to keep around (like using a lot of RAM). Some of the resources allocated via the fixture are just needed for a single test and some are better shared between test because allocation takes time. Seems simple enough, I'll just define two fixtures with different scopes which share the actual implementation:
import pytest
def _fixture_impl(request):
print('enter')
yield
print('leave')
@pytest.fixture(scope='function')
def the_function_fixture():
yield from _fixture_impl()
@pytest.fixture(scope='module')
def the_module_fixture():
yield from _fixture_impl()
@pytest.mark.parametrize('a', range(3))
def test_foo(the_module_fixture, the_function_fixture, a):
print(a)
This works as expected. One of the fixtures gets set up and torn down once, the other for each test:
$ pytest -xs test.py
============================= test session starts ==============================
platform darwin -- Python 3.5.3, pytest-3.0.7, py-1.4.33, pluggy-0.4.0
rootdir: /Users/michi/test-pytest, inifile: pytest.ini
collected 3 items
test.py enter
enter
0
.leave
enter
1
.leave
enter
2
.leave
leave
=========================== 3 passed in 0.02 seconds ===========================
But, I thought, I can shorten that code! Just apply the fixture()
decorator to the function twice!
import pytest
def _fixture_impl():
print('enter')
yield
print('leave')
the_function_fixture = pytest.fixture(scope='function')(_fixture_impl)
the_module_fixture = pytest.fixture(scope='module')(_fixture_impl)
@pytest.mark.parametrize('a', range(3))
def test_foo(the_module_fixture, the_function_fixture, a):
print(a)
But this has the unfortunate side effect that now both fixtures are just set up and torn down once:
$ pytest -xs test.py
============================= test session starts ==============================
platform darwin -- Python 3.5.3, pytest-3.0.7, py-1.4.33, pluggy-0.4.0
rootdir: /Users/michi/test-pytest, inifile: pytest.ini
collected 3 items
test.py enter
enter
0
.1
.2
.leave
leave
=========================== 3 passed in 0.02 seconds ===========================
It seems that the scope is declared for the function implementing the fixture and not once for each invocation of the decorator.
I did not expect that behavior. I would have assumed that the two versions would work equivalently. I do not know whether this usage pattern of the fixture()
decorator is common. In my case it saves a bit redundant code as the fixture in question uses a lot of other fixtures, and *args
does not work in this case. :)
This happens at least with pytest 3.0.7 on OS X 10.11.6. I'm happy to test more combinations, if necessary.
Installed packages:
$ pip list
DEPRECATION: The default format will switch to columns in the future. You can use --format=(legacy|columns) (or define a format=(legacy|columns) in your pip.conf under the [list] section) to disable this warning.
appdirs (1.4.3)
packaging (16.8)
pip (9.0.1)
py (1.4.33)
pyparsing (2.2.0)
pytest (3.0.7)
setuptools (34.3.3)
six (1.10.0)
wheel (0.30.0a0)