pythondependenciespytestpytest-dependency

How to impose order on fixtures in pytest?


I am trying to use pytest-dependency to make fixtures happen in order, regardless of how they are named, and regardless of the order in which they appear in a test's argument list.

The reason I need this, is to create fixtures that require initializations, that depend on other fixtures that require initializations, and they must happen in order. I have quite a few of these, and I don't want to rely on naming or on order in the argument list.

I also don't want to use pytest_sessionstart, because it can't take fixture inputs, which causes very unclean code.


The trivial example in the doc shows how to create programmed dependencies for tests:

import pytest

@pytest.mark.dependency()
@pytest.mark.xfail(reason="deliberate fail")
def test_a():
    assert False

@pytest.mark.dependency()
def test_b():
    pass

@pytest.mark.dependency(depends=["test_a"])
def test_c():
    pass

@pytest.mark.dependency(depends=["test_b"])
def test_d():
    pass

@pytest.mark.dependency(depends=["test_b", "test_c"])
def test_e():
    pass

This works with output:

============================= test session starts =============================
collecting ... collected 5 items

test_sanity.py::test_z XFAIL (deliberate fail)                           [ 20%]
@pytest.mark.dependency()
    @pytest.mark.xfail(reason="deliberate fail")
    def test_z():
>       assert False
E       assert False

test_sanity.py:6: AssertionError

test_sanity.py::test_x PASSED                                            [ 40%]
test_sanity.py::test_c SKIPPED (test_c depends on test_z)                [ 60%]
Skipped: test_c depends on test_z

test_sanity.py::test_d PASSED                                            [ 80%]
test_sanity.py::test_w SKIPPED (test_w depends on test_c)                [100%]
Skipped: test_w depends on test_c


=================== 2 passed, 2 skipped, 1 xfailed in 0.05s ===================

Now I want to do the same for fixtures.

My attempt:

conftest.py:

import pytest

pytest_plugins = ["dependency"]


@pytest.mark.dependency()
@pytest.fixture(autouse=True)
def zzzshould_happen_first():
    assert False


@pytest.mark.dependency(depends=["zzzshould_happen_first"])
@pytest.fixture(autouse=True)
def should_happen_last():
    assert False

and test_sanity.py:

def test_nothing():
    assert True

Outputs

test_sanity.py::test_nothing ERROR                                       [100%]
test setup failed
@pytest.mark.dependency(depends=["zzzshould_happen_first"])
    @pytest.fixture(autouse=True)
    def should_happen_last():
>       assert False
E       assert False

conftest.py:15: AssertionError

I expected the error on zzzshould_happen_first.


Is there a way to impose ordering on fixtures, such that

  1. Their name is ignored
  2. Their order in the argument list is ignored
  3. Other pytest features such as autouse can still be applied

Solution

  • You can give a fixture as a dependency directly with pytest. Something like this:

    import pytest
    
    
    @pytest.fixture(autouse=True)
    def zzzshould_happen_first():
        assert False
    
    
    @pytest.fixture(autouse=True)
    def should_happen_last(zzzshould_happen_first):
        assert False
    
    
    def test_nothing():
        assert True
    

    It gives what you want:

    test setup failed
    @pytest.fixture(autouse=True)
        def zzzshould_happen_first():
    >       assert False
    E       assert False
    
    answer.py:7: AssertionError