pytest: Unexpected order of tests using parameterized fixtures
Consider following code:
import pytest
@pytest.fixture(scope="function", params=(1, 2, 3))
def f1(request):
pass
@pytest.fixture(scope="function", params=('a', 'b', 'c'))
def f2(request):
pass
def test(f1, f2):
pass
The order of the tests meets my expectations:
============================= test session starts =============================
platform win32 -- Python 2.7.12, pytest-3.2.3, py-1.4.34, pluggy-0.4.0 -- c:\users\rbierbasz\.virtualenvs\core\scripts\python.exe
cachedir: .cache
rootdir: C:\Users\rbierbasz\repos\galaxy-core, inifile:
collected 9 items
test_order.py::test[1-a] PASSED
test_order.py::test[1-b] PASSED
test_order.py::test[1-c] PASSED
test_order.py::test[2-a] PASSED
test_order.py::test[2-b] PASSED
test_order.py::test[2-c] PASSED
test_order.py::test[3-a] PASSED
test_order.py::test[3-b] PASSED
test_order.py::test[3-c] PASSED
========================== 9 passed in 0.04 seconds ===========================
But when I changed fixtures’ scope from function to module:
import pytest
@pytest.fixture(scope="module", params=(1, 2, 3))
def f1(request):
pass
@pytest.fixture(scope="module", params=('a', 'b', 'c'))
def f2(request):
pass
def test(f1, f2):
pass
it seems to get random:
============================= test session starts =============================
platform win32 -- Python 2.7.12, pytest-3.2.3, py-1.4.34, pluggy-0.4.0 -- c:\users\rbierbasz\.virtualenvs\core\scripts\python.exe
cachedir: .cache
rootdir: C:\Users\rbierbasz\repos\galaxy-core, inifile:
collected 9 items
test_order.py::test[1-a] PASSED
test_order.py::test[1-b] PASSED
test_order.py::test[2-b] PASSED
test_order.py::test[2-a] PASSED
test_order.py::test[2-c] PASSED
test_order.py::test[1-c] PASSED
test_order.py::test[3-c] PASSED
test_order.py::test[3-b] PASSED
test_order.py::test[3-a] PASSED
========================== 9 passed in 0.04 seconds ===========================
The same happens for class and session scopes. It leads to fixtures being set up and torn down more times than necessary.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 1
- Comments: 23 (13 by maintainers)
@kchomski-reef thanks for the great insight. I haven’t checked
reorder_itemscode yet, but your reasoning seems correct. I only think that the assumptions on which this functionality is based are naive - that all paremetrized fixtures have the same weight. In real worldf1fixture from my example can have much more expensive setup/teardown, or there can be more fixtures depending on it. It would be great if I could control the order somehow. I tried indirect parametrization:But it breaks fixtures’ scopes (#570). The only working solutions for me now is moving one parametrized fixture to higher scope:
But it seems hacky and it’s not scalable. Is there any way of achieving it? Some hook maybe?
Good point to have a new issue rather than stuck in a closed ticket. #3393 created.
@kchomski-reef thanks for the interest.
You are half right: the purpose is to reorder test itemswithin a scope to minimize fixture setup/teardown, when those fixtures are parametrized.
For example, consider this session fixture:
Consider this test file:
If we don’t do any reordering, the tests would execute in this order:
IOW, this would cause
session_fixto be created with parameter1fortest_uses_fix_1, then be destroyed so a newsession_fixcan be created with parameter2and executetest_uses_fix_1again with the new fixture. The same happens fortest_uses_fix_2and for every other test which uses those fixtures.A key fact to understand all this and that is not clear in the documentation is that at any given time only a single instance of
session_fixcan exist, that’s why it needs to be destroyed between each test function call which parametrizes it.The reorder algorithm thus tries to reorder the tests to minimize fixture setup/teardown:
This order now allow us to create
session_fix(1)once, executetest_uses_fix_1andtest_uses_fix_2with that fixture, then createsession_fix(2)and execute the tests, and so on.The same is valid for the other scopes other than function.
Let me know if something is not clear on my explanation.