Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelog/10156.doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Added a documentation example showing how to build dynamic session-scoped
parametrized fixtures whose ``params`` depend on command-line options.
76 changes: 75 additions & 1 deletion doc/en/example/special.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,79 @@
.. _`dynamic session-scoped fixtures`:

Building dynamic session-scoped parametrized fixtures
------------------------------------------------------

Sometimes you need a session-scoped fixture whose ``params`` depend on
command-line arguments or other runtime configuration that isn't available
when ``conftest.py`` is first imported. A plain ``@pytest.fixture`` definition
cannot do this, because fixture ``params`` are evaluated at import time, before
:func:`pytest_configure` runs.

The solution is to register a *plugin class* containing the fixture inside
:func:`pytest_configure`. At that point the command-line options have already
been parsed, so you can build the ``params`` list dynamically.

.. code-block:: python

# content of conftest.py

import pytest


def pytest_addoption(parser):
parser.addoption(
"--servers",
default="localhost",
help="Comma-delimited list of servers to run tests against.",
)


def pytest_configure(config):
# Options are available here, after argument parsing.
server_list = [s.strip() for s in config.getoption("--servers").split(",")]

class DynamicFixturePlugin:
@pytest.fixture(scope="session", params=server_list)
def server_hostname(self, request):
"""Parametrized session-scoped fixture built from --servers."""
return request.param

config.pluginmanager.register(DynamicFixturePlugin(), "server-hostname-fixture")

Now any test that requests ``server_hostname`` will be run once per server:

.. code-block:: python

# content of test_servers.py


def test_responds(server_hostname):
assert server_hostname # replace with real connection logic

Running with the default (one server):

.. code-block:: pytest

$ pytest -q test_servers.py
.
1 passed in 0.12s

Running against multiple servers:

.. code-block:: pytest

$ pytest -q test_servers.py --servers=host1,host2
..
2 passed in 0.12s

.. note::

The plugin class can contain multiple fixtures. Each fixture defined on the
class is treated exactly like a fixture in ``conftest.py`` — the ``self``
parameter is the plugin instance and is not passed to the test.

A session-fixture which can look at all collected tests
----------------------------------------------------------------
-------------------------------------------------------

A session-scoped fixture effectively has access to all
collected test items. Here is an example of a fixture
Expand Down
Loading