Skip to content

Question re: order of execution of test fixtures #2861

Closed
@TheFriendlyCoder

Description

@TheFriendlyCoder

Good day.

This is probably more of a question than a bug, but I'm curious if there are any docs describing the order of execution of test fixtures in pytest?

Specifically, I have the following use case / problem: I have 3 test fixtures I'm trying to organize:

  1. (fixture1) Function scoped fixture with auto-use enabled. This one configures logging for each unit test so output for each test gets redirected to a different log file. I set the fixture to autouse because I want this log redirection to happen automatically for every unit test.
  2. (fixture2) Session scoped fixture with auto-use disabled. This one sets up some heavy weight configuration that should only be run once per test session to conserve resources. I set auto-use to false since I only want to do this setup for tests that require it.
  3. (fixture3) Function scoped fixture with auto-use disabled. This fixture depends on the previous one, taking parts of the session wide test configuration and adding some function-specific bits to it that each test will require. Thus, test functions should never need to explicitly mark the session scoped fixture, but instead link to this function scoped one which, in turn should automatically run the session scoped fixture as necessary.

Now, most of this use case is pretty easy to orchestrate but here's where my problem lies. For tests that use fixture3, I need the 3 fixtures to run in the following order: fixture2, fixture1, fixture3. I can't seem to find a solution that ensures this order of execution whilst using the auto-use flag for fixture1. In every case fixture1 always runs first. Can someone perhaps explain what I might be doing wrong or how to get the desired behavior?

Here's a snippet of code that illustrates what my current implementation looks like:

@pytest.fixture(scope='function', autouse=True)
def config_test_logger(request):
    # (fixture1) 
    # configure a per-test logger for every test

@pytest.fixture(scope='session')
def setup_env():
    # (fixture2) 
    # configure heavy weight test setup logic, once per session and only for tests that need it
    # test should never directly depend on this fixture, but rather inherit this one indirectly
    # by using the test_env fixture defined below

@pytest.fixture(scope='function')
def test_env(setup_env, request):
    # (fixture3)
    # make sure our heavy weight session setup is done first, then customize the env with
    # test specific bits. Unit tests should only need to depend on this fixture when they need
    # to interact with the heave weight session stuff

The closest solution I found to get the desired behavior is to disable the autouse flag on fixture1 (aka: config_test_logger) and add an explicit dependency on this fixtures to fixture3 (aka: test_env) like this:

@pytest.fixture(scope='function')
def config_test_logger(request):
    # (fixture1) 
    # configure a per-test logger, now must be explicitly included by each test

@pytest.fixture(scope='session')
def setup_env():
    # (fixture2) 
    # configure heavy weight test setup logic, once per session and only for tests that need it

@pytest.fixture(scope='function')
def test_env(setup_env, config_test_logger, request):
    # (fixture3)
    # make sure our heavy weight session setup is done first, then customize the env with
    # test specific bits. Unit tests should only need to depend on this fixture when they need
    # to interact with the heave weight session stuff

This slight variation has the benefit of ensuring the order of execution of the fixtures is correct (ie: fixture2, fixture1, fixture3) but has the down side of requiring every other unit test in the suite to explicitly mark a dependency on fixture1, which is overly verbose and fragile at best.

I've also tried several variations of this including explicitly listing config_test_logger as a dependent fixture in test_env and leaving the autouse flag enabled on the former, renaming the fixture methods so they follow an alphabetical ordering (ie: a_setup_env, b_test_env, c_config_test_logger) just in case the ordering was alphabetic, and several other things but I can't seem to find a solution that gets me exactly what I'm looking for.

Any help anyone has would be greatly appreciated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: fixturesanything involving fixtures directly or indirectlytype: questiongeneral question, might be closed after 2 weeks of inactivity

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions