diff --git a/doc/en/example/parametrize.rst b/doc/en/example/parametrize.rst index 8e7e58f9829..02f747566de 100644 --- a/doc/en/example/parametrize.rst +++ b/doc/en/example/parametrize.rst @@ -349,6 +349,8 @@ And then when we run the test: The first invocation with ``db == "DB1"`` passed while the second with ``db == "DB2"`` failed. Our ``db`` fixture function has instantiated each of the DB values during the setup phase while the ``pytest_generate_tests`` generated two according calls to the ``test_db_initialized`` during the collection phase. +.. _`indirect parametrization`: + Indirect parametrization --------------------------------------------------- diff --git a/doc/en/how-to/fixtures.rst b/doc/en/how-to/fixtures.rst index 0ffc0778f9f..7b1045adf4b 100644 --- a/doc/en/how-to/fixtures.rst +++ b/doc/en/how-to/fixtures.rst @@ -1260,6 +1260,55 @@ If the data created by the factory requires managing, the fixture can take care customer_3 = make_customer_record("Meredith") +.. _`passing-parameters-to-fixtures`: + + +Passing arguments to fixture functions +----------------------------------------------------------------- + +Sometimes a test needs to configure a fixture in a specific way that +shouldn't affect other tests using the same fixture. For example, a +test might need a database connection to a particular host, or a +service to be started with specific command-line arguments. + +pytest provides a way to pass arguments to fixture functions from +individual tests using :ref:`indirect parametrization +`. The fixture function receives the +argument via the built-in :py:class:`request ` +fixture as :py:attr:`request.param`. + +.. code-block:: python + + import pytest + + + @pytest.fixture + def service(request): + # request.param carries the value passed from the test + return f"Service launched with {request.param!r}" + + + @pytest.mark.parametrize("service", ["--verbose"], indirect=True) + def test_with_service(service): + assert service == "Service launched with '--verbose'" + +The ``indirect=True`` flag tells pytest that the parametrized argument +``service`` should be passed to the ``service`` fixture function (as +``request.param``) rather than being injected directly into the test +function. + +This is particularly useful when: + +* A fixture has a default configuration but a specific test needs a + different one. +* The parameter value is only relevant to one test and shouldn't cause + other tests using the same fixture to run multiple times. + +For more details and examples, including how to pass parameters to +multiple fixtures at once, see the :ref:`indirect parametrization +` section in the parametrize documentation. + + .. _`fixture-parametrize`: Parametrizing fixtures diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 7656fca2f5b..44f3f336ab0 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -1567,6 +1567,26 @@ def fixture( of the fixture function and all of the tests using it. The current parameter is available in ``request.param``. + Parameters can also be passed to a fixture from a specific test using + :ref:`indirect parametrization `. This is + useful when a test needs to configure a fixture in a way that shouldn't + affect other tests using the same fixture. For example:: + + import pytest + + + @pytest.fixture + def service(request): + return f"Service launched with {request.param!r}" + + + @pytest.mark.parametrize("service", ["--verbose"], indirect=True) + def test_with_service(service): + assert service == "Service launched with '--verbose'" + + See the :ref:`indirect parametrization` section in the parametrize + documentation for more details and examples. + :param autouse: If True, the fixture func is activated for all tests that can see it. If False (the default), an explicit reference is needed to activate