Search code examples
pythondynamicruntimepytestfixtures

Pytest - dynamic resolution of fixtures' dependencies


I cannot find a solution to alter fixtures dependency in any different way than this bellow. The problem is that I need to determine the dependencies basing on pytest.config.getoption argument, instead of what's used here (variable resolved at module level).

I need to get two modes of testing: fast and full, keeping the same test source code.

pytest_generate_tests seems to be useless, or at least I don't know how to use it here.

import pytest


DO_FULL_SETUP = "some condition that I need take from request.config.getoption(), not like this"

if DO_FULL_SETUP:
    # such a distinction is valid from interpreter's (and pytest's) point of view

    @pytest.fixture(scope="session")
    def needed_environment(a_lot_of, expensive, fixtures_needed):
        """This does expensive setup that I need 
        to avoid in "fast" mode. Takes about a minute (docker pull, etc..)"""

else:
    @pytest.fixture
    def needed_environment():
        """This does a fast setup, has "function scope" 
        and doesn't require any additional fixtures. Takes ~20ms"""


def test_that_things(needed_environment):
    """At this moment I don't want to distinguish what 
     needed_environment is. Tests have to pass in both modes."""

Solution

  • This can be done using request.getfixturevalue('that_fixture_name'). Fixtures can be invoked in runtime. There is even no fixture's scope violation in this case ('session' vs. 'function').

    import pytest
    
    
    @pytest.fixture(scope="session")
    def needed_environment_full(a_lot_of, expensive, fixtures_needed):
        """This does expensive setup that I need
        to avoid in "fast" mode. Takes about a minute (docker pull, etc..)"""
    
    
    @pytest.fixture
    def needed_environment_fast():
        """This does a fast setup, has "function scope"
        and doesn't require any additional fixtures. Takes ~20ms"""
    
    
    @pytest.fixture
    def needed_environment(request):
        """Dynamically run a named fixture function, basing on cli call argument."""
        if request.config.getoption('--run_that_fast'):
            return request.getfixturevalue('needed_environment_fast')
        else:
            return request.getfixturevalue('needed_environment_full')
    
    
    def test_that_things(needed_environment):
        """At this moment I don't want to distinguish what
         needed_environment is. Tests have to pass in both modes."""