mark.usefixtures only seems to work on tests directly, not within other fixtures, which is I assume part of whats going on here.

For this case, you could fall back to request.getfixturevalue

Dynamically run a named fixture function. Declaring fixtures via function argument is recommended where possible. But if you can only decide whether to use another fixture at test setup time, you may use this function to retrieve it inside a fixture or test function body.

@pytest.fixture
def bar_fixture():
    do_something_but_Return_no_value()

@pytest.mark.parametrize(
    ["foo", "fixtures"],
    [
        pytest.param(
            True, [], marks=[pytest.mark.test_1],
        ),
        pytest.param(
            False, ["bar_fixture"], marks=[pytest.mark.test_2]
        ),
    ],
)
def test_foo(request, foo, fixtures):
    for fixture in fixtures:
        request.getfixturevalue(fixture)

    func(foo)

This obviously isn't as elegant as other options, but its easy enough to follow.

Answer from flakes on Stack Overflow
🌐
pytest
docs.pytest.org › en › 7.1.x › reference › reference.html
API Reference — pytest documentation
The name of the fixture function can later be referenced to cause its invocation ahead of running tests: test modules or classes can use the pytest.mark.usefixtures(fixturename) marker.
🌐
pytest
docs.pytest.org › en › stable › how-to › fixtures.html
How to use fixtures - pytest documentation
# content of pytest.toml [pytest] usefixtures = ["cleandir"] ... Note this mark has no effect in fixture functions.
🌐
pytest
docs.pytest.org › en › stable › how-to › mark.html
How to mark test functions with attributes - pytest documentation
You can find the full list of builtin markers in the API Reference. Or you can list all the markers, including builtin and custom, using the CLI - pytest --markers. Here are some of the builtin markers: usefixtures - use fixtures on a test function or class ·
🌐
GitHub
github.com › pytest-dev › pytest › issues › 3308
Question: Can someone explain the below uses of @pytest.mark.usefixtures · Issue #3308 · pytest-dev/pytest
March 14, 2018 - @pytest.fixture() def populateList(f): assert 1 == 0 @pytest.mark.usefixtures("populateList") def test_1(): assert 0 == 0
Author   thakkardharmik
🌐
Astral
docs.astral.sh › ruff › rules › pytest-fixture-param-without-value
pytest-fixture-param-without-value (PT019) | Ruff
If the test function depends on the fixture being activated, but does not use it in the test body or otherwise rely on its return value, prefer the @pytest.mark.usefixtures decorator, to make the dependency explicit and avoid the confusion caused by unused arguments.
🌐
pytest
docs.pytest.org › en › stable › reference › reference.html
API Reference - pytest documentation
The name of the fixture function can later be referenced to cause its invocation ahead of running tests: test modules or classes can use the pytest.mark.usefixtures(fixturename) marker.
Find elsewhere
🌐
pytest
docs.pytest.org › en › 6.2.x › explanation › fixtures.html
pytest fixtures: explicit, modular, scalable — pytest documentation
Due to the usefixtures marker, the cleandir fixture will be required for the execution of each test method, just as if you specified a “cleandir” function argument to each of them.
🌐
Rednafi
rednafi.com › python › inject-pytest-fixture
Injecting Pytest fixtures without cluttering test signatures | Redowan's Reflections
December 2, 2024 - Clean up pytest test signatures using @pytest.mark.usefixtures to inject implicit fixtures without autouse or unused parameter warnings.
🌐
O'Reilly
oreilly.com › library › view › python-testing-with › 9781680502848 › f_0036.xhtml
Python Testing with pytest - Python Testing with pytest [Book]
September 15, 2017 - You can also mark a test or a class with @pytest.mark.usefixtures(’fixture1’, ’fixture2’). usefixtures takes a string that is composed of a comma-separated list of fixtures to use.
Author   Brian Okken
Published   2017
Pages   222
Top answer
1 of 2
10

Use the usefixtures marker:

# conftest.py
import pytest

@pytest.fixture
def mocks(mocker):
    mocker.patch('os.path.isdir', return_value=True)

# test_me.py
import os
import pytest

@pytest.mark.usefixtures('mocks')
def test_mocks():
    assert os.path.isdir('/this/is/definitely/not/a/dir')

Passing multiple fixtures is also posible:

@pytest.mark.usefixtures('mocks', 'my_other_fixture', 'etc')

However, there is a caveat: the mocks fixture in your code returns a value ret_val. When passing the fixture via test function args, this value is returned under the mocks arg; when you use markers, you don't have the arg anymore, so you won't be able to use the value. Should you be needing the mock value, pass the fixture in the test function args. There are some other ways imaginable, like passing ret_val via cache, however, the resulting code will be more complicated and less readable so I wouldn't bother.

2 of 2
9

I was able to implement this by using the pytest_collection_modifyitems hook to adjust the list of fixtures on the test item after collection:

@pytest.hookimpl(trylast=True)
def pytest_collection_modifyitems(items):
    '''
    Check if any tests are marked to use the mock.
    '''
    for item in items:
        if item.get_closest_marker('mocks'):
            item.fixturenames.append('mocks')

Adjusting the Item.fixturenames list after collection appears to trigger the fixture setup in the way I was hoping.

If you don't care about using a custom mark, however, @hoefling's recommendation to use the built-in usefixtures mark would be a good solution, too.

🌐
PythonTest
pythontest.com › framework › pytest › pytest-mark-usefixtures
Using pytest fixtures with mark.usefixtures | PythonTest
July 12, 2025 - However, this is what it’d look like to mark individual tests: # test_usefixtures.py import pytest @pytest.fixture() def before(): print('\nbefore each test') @pytest.mark.usefixtures("before") def test_1(): ...
🌐
Astral
docs.astral.sh › ruff › rules › pytest-erroneous-use-fixtures-on-fixture
pytest-erroneous-use-fixtures-on-fixture (PT025) | Ruff
import pytest @pytest.fixture() def a(): pass @pytest.mark.usefixtures("a") @pytest.fixture() def b(a): pass
🌐
pytest
docs.pytest.org › en › stable › example › markers.html
Working with custom markers - pytest documentation
Example: @parametrize('arg1', [1,2]) ... for more info and examples. @pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures....
🌐
GitHub
github.com › pytest-dev › pytest › issues › 6908
add pytest.mark.usefixtures mark in a hook not effective · Issue #6908 · pytest-dev/pytest
March 12, 2020 - import something assert something.Foo.stuff == {"foo", "bar"} @pytest.mark.foobar("foo", "bar") @pytest.mark.usefixtures("prepare_something") def test_foo_works(request): assert request.node.own_markers == [ pytest.mark.usefixtures("prepare_something").mark, pytest.mark.foobar("foo", "bar").mark, ] from .
Author   diefans
🌐
Testmu
testmu.ai › testmu ai › blog › pytest fixtures: a detailed guide with examples | testmu ai
pytest Fixtures: A Detailed Guide With Examples | TestMu AI (Formerly LambdaTest)
January 11, 2026 - The pytest fixture function is automatically called by the pytest framework when the name of the argument and the fixture is the same. A function is marked as fixture using the following marker:
Top answer
1 of 6
33

Both Pytest Fixtures and regular functions can be used to structure to test code and reduce code duplication. The answer provided by George Udosen does an excellent job explaining that.

However, the OP specifically asked about the differences between a pytest.fixture and a regular Python function and there is a number of differences:

Pytest Fixtures are scoped

By default, a pytest.fixture is executed for each test function referencing the fixture. In some cases, though, the fixture setup may be computationally expensive or time consuming, such as initializing a database. For that purpose, a pytest.fixture can be configured with a larger scope. This allows the pytest.fixture to be reused across tests in a module (module scope) or even across all tests of a pytest run (session scope). The following example uses a module-scoped fixture to speed up the tests:

from time import sleep
import pytest


@pytest.fixture(scope="module")
def expensive_setup():
    return sleep(10)

def test_a(expensive_setup):
    pass  # expensive_setup is instantiated for this test

def test_b(expensive_setup):
    pass  # Reuses expensive_setup, no need to wait 10s

Although different scoping can be achieved with regular function calls, scoped fixtures are much more pleasant to use.

Pytest Fixtures are based on dependency injection

Pytest registers all fixtures during the test collection phase. When a test function requires an argument whose name matches a registered fixture name, Pytest will take care that the fixture is instantiated for the test and provide the instance to the test function. This is a form of dependency injection.

The advantage over regular functions is that you can refer to any pytest.fixture by name without having to explicitly import it. For example, Pytest comes with a tmp_path fixture that can be used by any test to work with a temporary file. The following example is taken from the Pytest documentation:

CONTENT = "content"


def test_create_file(tmp_path):
    d = tmp_path / "sub"
    d.mkdir()
    p = d / "hello.txt"
    p.write_text(CONTENT)
    assert p.read_text() == CONTENT
    assert len(list(tmp_path.iterdir())) == 1
    assert 0

The fact that users don't have to import tmp_path before using it is very convenient.

It is even possible to apply a fixture to a test function without the test function requesting it (see Autouse fixtures).

Pytest fixtures can be parametrized

Much like test parametrization, fixture parametrization allows the user to specify multiple "variants" of a fixture, each with a different return value. Every test using that fixture will be executed multiple times, once for each variant. Say you want to test that all your code is tested for HTTP as well as HTTPS URLs, you might do something like this:

import pytest


@pytest.fixture(params=["http", "https"])
def url_scheme(request):
    return request.param


def test_get_call_succeeds(url_scheme):
    # Make some assertions
    assert True

The parametrized fixture will cause each referencing test to be executed with each version of the fixture:

$ pytest
tests/test_fixture_param.py::test_get_call_succeeds[http] PASSED                                                                                                                                                                         [ 50%]
tests/test_fixture_param.py::test_get_call_succeeds[https] PASSED                                                                                                                                                                        [100%]

======== 2 passed in 0.01s ========

Conclusion

Pytest fixtures provide many quality-of-life improvements over regular function calls. I recommend to always prefer Pytest fixtures over regular functions, unless you must be able to call the fixture directly. Directly invoking pytest fixtures is not indended and the call will fail.

2 of 6
7

A fixture is used:

  • to have a specific function to be used many times and to simplify a test.

  • to do something before stating and after finishing test with yield.

For example, there are test_get_username() and test_set_check_password() in Django as shown below:

import pytest

from django.contrib.auth.models import User

@pytest.mark.django_db
def test_get_username():
    user = User.objects.create_user("test-user")
    user.username = "John"
    assert user.get_username() == "John"

@pytest.mark.django_db
def test_set_password_and_check_password():
    user = User.objects.create_user("test-user")
    user.set_password("new-password")
    assert user.check_password("new-password") == True

Then, you can create and use user() with @pytest.fixture to use it many times and to simplify test_get_username() and test_set_password_and_check_password() as shown below:

import pytest

from django.contrib.auth.models import User

@pytest.fixture # Here
def user():
    user = User.objects.create_user("test-user")
    return user

@pytest.mark.django_db
def test_get_username(user): # <- user
    user.username = "John"
    assert user.get_username() == "John"

@pytest.mark.django_db
def test_set_password_and_check_password(user): # <- user
    user.set_password("new-password")
    assert user.check_password("new-password") == True

And, for example, there are fixture_1() with yield and test_1() as shown below:

import pytest

@pytest.fixture
def fixture_1():
    print('Before Test')
    yield 6
    print('After Test')

def test_1(fixture_1):
    print('Running Test')
    assert fixture_1 == 6

Then, this is the output below:

$ pytest -q -rP
.                               [100%]
=============== PASSES ===============
_______________ test_1 _______________
------- Captured stdout setup --------
Before Test
-------- Captured stdout call --------
Running Test
------ Captured stdout teardown ------
After Test
1 passed in 0.10s

In addition, you can run multiple fixtures for test_1() and test_2() as shown below. *My answer explains how to call a fixture from another fixture in Pytest and my answer explains how to pass parameters or arguments to a fixture in Pytest and my answer explains how to use a fixture with @pytest.mark.parametrize() and my answer explains how to use fixtures as arguments in @pytest.mark.parametrize():

import pytest

@pytest.fixture
def fixture_1():
    return "fixture_1"

@pytest.fixture
def fixture_2():
    return "fixture_2"

def test_1(fixture_1, fixture_2):
    print(fixture_1, fixture_2)
    assert True

def test_2(fixture_1, fixture_2):
    print(fixture_1, fixture_2)
    assert True

Then, this is the output below:

$ pytest -q -rP
..                               [100%]
=============== PASSES ================ 
_______________ test_1 ________________ 
-------- Captured stdout call --------- 
fixture_1 fixture_2
_______________ test_2 ________________ 
-------- Captured stdout call --------- 
fixture_1 fixture_2
2 passed in 0.33s

And, you can use request.getfixturevalue() to run fixture_1() and fixture_2() in test_1() and test_2() as shown below:

import pytest

@pytest.fixture
def fixture_1():
    return "fixture_1"

@pytest.fixture
def fixture_2():
    return "fixture_2"

def test_1(request):
    print(request.getfixturevalue("fixture_1"))
    print(request.getfixturevalue("fixture_2"))
    assert True

def test_2(request):
    print(request.getfixturevalue("fixture_1"))
    print(request.getfixturevalue("fixture_2"))
    assert True

Then, this is the output below:

$ pytest -q -rP
..                               [100%]
=============== PASSES ================ 
_______________ test_1 ________________ 
-------- Captured stdout call --------- 
fixture_1
fixture_2
_______________ test_2 ________________ 
-------- Captured stdout call --------- 
fixture_1
fixture_2
2 passed in 0.10s

And, you can use @pytest.fixture(autouse=True) to run fixtures for all the tests test_1() and test_2() without setting fixtures as the tests' parameters as shown below. *A test cannot use fixtures' return values without fixtures' parameters:

import pytest

@pytest.fixture(autouse=True)
def fixture_1():
    print("fixture_1")

@pytest.fixture(autouse=True)
def fixture_2():
    print("fixture_2")

def test_1():
    assert True

def test_2():
    assert True

Then, this is the output below:

$ pytest -q -rP
..                               [100%]
=============== PASSES ================ 
_______________ test_1 ________________ 
-------- Captured stdout setup -------- 
fixture_1
fixture_2
_______________ test_2 ________________ 
-------- Captured stdout setup -------- 
fixture_1
fixture_2
2 passed in 0.33s

And, you can use @pytest.mark.usefixtures for test_1() and test_2() to run multiple fixtures as shown below. *A test cannot use fixtures' return values without fixtures' parameters:

import pytest

@pytest.fixture
def fixture_1():
    print("fixture_1")

@pytest.fixture
def fixture_2():
    print("fixture_2")

@pytest.mark.usefixtures('fixture_1', 'fixture_2')
def test_1():
    assert True

@pytest.mark.usefixtures('fixture_1', 'fixture_2')
def test_2():
    assert True

Then, this is the output below:

$ pytest -q -rP
..                               [100%]
=============== PASSES ================ 
_______________ test_1 ________________ 
-------- Captured stdout setup -------- 
fixture_1
fixture_2
_______________ test_2 ________________ 
-------- Captured stdout setup -------- 
fixture_1
fixture_2
2 passed in 0.33s

And, you can use @pytest.mark.usefixtures for test_1() and test_2() in Test class to run multiple fixtures as shown below. *A fixture can use request.cls.something to pass data to the tests in a class:

import pytest

@pytest.fixture
def fixture_1(request):
    request.cls.first_name = "John"

@pytest.fixture
def fixture_2(request):
    request.cls.last_name = "Smith"

@pytest.mark.usefixtures('fixture_1', 'fixture_2')
class Test:
    def test_1(self):
        print(self.first_name, self.last_name)
        assert True

    def test_2(self):
        print(self.first_name, self.last_name)
        assert True

Then, this is the output below:

$ pytest -q -rP
..                               [100%]
=============== PASSES ================ 
_____________ Test.test_1 _____________ 
-------- Captured stdout call --------- 
John Smith
_____________ Test.test_2 _____________ 
-------- Captured stdout call --------- 
John Smith
2 passed in 0.32s

And, you can use @pytest.fixture(autouse=True) to run fixtures for all the tests test_1() and test_2() in Test class without setting fixtures as the tests' parameters as shown below. *A fixture can use request.cls.something to pass data to the tests in a class:

import pytest

@pytest.fixture
def fixture_1(request):
    request.cls.first_name = "John"

@pytest.fixture
def fixture_2(request):
    request.cls.last_name = "Smith"

@pytest.mark.usefixtures('fixture_1', 'fixture_2')
class Test:
    def test_1(self):
        print(self.first_name, self.last_name)
        assert True

    def test_2(self):
        print(self.first_name, self.last_name)
        assert True

Then, this is the output below:

$ pytest -q -rP
..                               [100%]
=============== PASSES ================ 
_____________ Test.test_1 _____________ 
-------- Captured stdout call --------- 
John Smith
_____________ Test.test_2 _____________ 
-------- Captured stdout call --------- 
John Smith
2 passed in 0.33s
🌐
seanh.cc
seanh.cc › 2017 › 03 › 17 › usefixtures-class-decorator
usefixtures as a Class Decorator - seanh.cc
March 17, 2017 - You also can put a @pytest.mark.usefixtures(...) decorator on a test class and pytest will automatically call those fixtures for every test method in the class, even if the methods themselves don’t take the fixtures as arguments.
🌐
Pythontest
podcast.pythontest.com › pytest-fixtures-nuts-bolts-revisited
pytest fixtures nuts and bolts - revisited | PythonTest
August 6, 2025 - Using pytest fixtures with mark.usefixtures · pytest fixture return value · pytest fixture teardown · pytest fixture scope · Parametrizing pytest fixtures with param · Using multiple pytest fixtures · Modularity: pytest fixtures using other fixtures · pytest session scoped fixtures ·