4

I'm using Python3.8 and pytest. How can I activate a fixture for my session based on some command line specification? Right now I have a tests/conftest.py file that includes

@pytest.fixture(name="fixture1", scope="session")
def fixture1():
    ...

@pytest.fixture(name="fixture2", scope="session")
def fixture2():
    ...

But I only want certain fixtures included in my session and I want to be able to specify that in either a pytest.ini file or via command line arguments I pass to pytest. How do I do that?

Edit: This is my use case ...

If the command line option is enabled, I'd like to depend on one fixture

@pytest.fixture(name="az_sql_db_inst")
def az_db_connection_fixture(az_sql_creds, wait_for_sql_server)

but if the command line isn't enabled, I'd like to depend on another fixture ...

@pytest.fixture(name="az_sql_db_inst")
def az_db_connection_fixture(az_sql_creds, wait_for_docker_sql_server)
Dave
  • 15,639
  • 133
  • 442
  • 830

1 Answers1

4

You can add command line flags that can be used to enable your fixtures:

conftest.py

def pytest_addoption(parser):
    parser.addoption('--option2', action='store_const', const=True)
    parser.addoption('--option2', action='store_const', const=True)

Than you have to check for these arguments in your fixture:

@pytest.fixture(name="fixture1", scope="session", autouse=True)
def fixture1(request):
   # only use with option1 command line argument
   if request.config.getoption("--option1"):
       ...
    
@pytest.fixture(name="fixture2", scope="session", autouse=True)
def fixture2(request):
   # only use with option2 command line argument
   if request.config.getoption("--option2"):
       ...

@pytest.fixture(name="fixture3", scope="session", autouse=True)
def fixture3(request):
   # only use if option1 command line argument is not provided
   if not request.config.getoption("--option1"):
       ...

I used autouse=True here as I expect that the fixtures execute different setup code, your usage may vary of course.

You are now able to call:

  • pytest -> no fixture will be applied
  • pytest --option1 -> fixture1 will be applied
  • pytest --option1 --option2 -> both fixtures will be applied

You can also add these arguments to your pytest.ini:

[pytest]
# always apply fixture2
addopts = --option2

EDIT:
As for the followup question about the inherited fixture, you can do something like this:

@pytest.fixture
def wait_for_sql_server(request):
   if request.config.getoption("--my_option"):
       ...

@pytest.fixture
def wait_for_docker(request):
   if not request.config.getoption("--my_option"):
       ...

@pytest.fixture(name="az_sql_db_inst")
def az_db_connection_fixture(
    az_sql_creds, wait_for_sql_server, wait_for_docker):
    ...

EDIT2:
If you are not able to write or adapt the base fixtures (wait_for_ in the EDIT part of the question) yourself, you can go a slighly other way.

You can write separate implementations of your base fixture in separate plugins, and load the needed plugin based on the configuration:

plugin_docker.py

@pytest.fixture
def wait_for_service(wait_for_docker):
    yield

plugin_server.py

@pytest.fixture
def wait_for_service(wait_for_sql_server):
    yield

conftest.py

def pytest_addoption(parser):
    parser.addoption('--docker', action='store_const', const=True)

def pytest_configure(config):    
    use_docker = config.getoption("--docker")
    plugin_name = 'plugin_docker' if use_docker else 'plugin_server'
    if not config.pluginmanager.has_plugin(plugin_name):
        config.pluginmanager.import_plugin(plugin_name)

@pytest.fixture(name="az_sql_db_inst")
def az_db_connection_fixture(az_sql_creds, wait_for_service):
    ...    

The wait_for_service fixtures are just a wrapper around the actual fixtures, but this way you can derive from the same fixture in both scenarios.

MrBean Bremen
  • 14,916
  • 3
  • 26
  • 46
  • Thanks so much for this. I'm trying to figure out how to rewrite what I have to fit into what you provided here, but i'm getting stuck (edit my question with the example). How would I use the command line option to make my fixture depend on a different fixture based on whether that command line option is provided? – Dave Aug 05 '20 at 20:15
  • I added this to the answer, please check if you can use it. – MrBean Bremen Aug 05 '20 at 20:52
  • Thanks for the expanded answer. Here's the rub -- I didn't write one of the fixtures (e.g. "wait_for_docker_sql_server"). This is a fixture that's get included by virtue of including a plugin. So I don't actually control the method body of "wait_for_docker_sql_server". Not sure if I can still apply what you have above. – Dave Aug 05 '20 at 23:24
  • Added another part to the answer. – MrBean Bremen Aug 06 '20 at 05:56