Is this the correct use of conftest.py?

Yes it is. Fixtures are a potential and common use of conftest.py. The fixtures that you will define will be shared among all tests in your test suite. However, defining fixtures in the root conftest.py might be useless and it would slow down testing if such fixtures are not used by all tests.

Does it have other uses?

Yes it does.

  • Fixtures: Define fixtures for static data used by tests. This data can be accessed by all tests in the suite unless specified otherwise. This could be data as well as helpers of modules which will be passed to all tests.

  • External plugin loading: conftest.py is used to import external plugins or modules. By defining the following global variable, pytest will load the module and make it available for its test. Plugins are generally files defined in your project or other modules which might be needed in your tests. You can also load a set of predefined plugins as explained here.

    pytest_plugins = "someapp.someplugin"

  • Hooks: You can specify hooks such as setup and teardown methods and much more to improve your tests. For a set of available hooks, read Hooks link. Example:

      def pytest_runtest_setup(item):
           """ called before ``pytest_runtest_call(item). """
           #do some stuff`
    
  • Test root path: This is a bit of a hidden feature. By defining conftest.py in your root path, you will have pytest recognizing your application modules without specifying PYTHONPATH. In the background, py.test modifies your sys.path by including all submodules which are found from the root path.

Can I have more than one conftest.py file?

Yes you can and it is strongly recommended if your test structure is somewhat complex. conftest.py files have directory scope. Therefore, creating targeted fixtures and helpers is good practice.

When would I want to do that? Examples will be appreciated.

Several cases could fit:

Creating a set of tools or hooks for a particular group of tests.

root/mod/conftest.py

def pytest_runtest_setup(item):
    print("I am mod")
    #do some stuff


test root/mod2/test.py will NOT produce "I am mod"

Loading a set of fixtures for some tests but not for others.

root/mod/conftest.py

@pytest.fixture()
def fixture():
    return "some stuff"

root/mod2/conftest.py

@pytest.fixture()
def fixture():
    return "some other stuff"

root/mod2/test.py

def test(fixture):
    print(fixture)

Will print "some other stuff".

Overriding hooks inherited from the root conftest.py.

root/mod/conftest.py

def pytest_runtest_setup(item):
    print("I am mod")
    #do some stuff

root/conftest.py

def pytest_runtest_setup(item):
    print("I am root")
    #do some stuff

By running any test inside root/mod, only "I am mod" is printed.

You can read more about conftest.py here.

EDIT:

What if I need plain-old helper functions to be called from a number of tests in different modules - will they be available to me if I put them in a conftest.py? Or should I simply put them in a helpers.py module and import and use it in my test modules?

You can use conftest.py to define your helpers. However, you should follow common practice. Helpers can be used as fixtures at least in pytest. For example in my tests I have a mock redis helper which I inject into my tests this way.

root/helper/redis/redis.py

@pytest.fixture
def mock_redis():
    return MockRedis()

root/tests/stuff/conftest.py

pytest_plugin="helper.redis.redis"

root/tests/stuff/test.py

def test(mock_redis):
    print(mock_redis.get('stuff'))

This will be a test module that you can freely import in your tests. NOTE that you could potentially name redis.py as conftest.py if your module redis contains more tests. However, that practice is discouraged because of ambiguity.

If you want to use conftest.py, you can simply put that helper in your root conftest.py and inject it when needed.

root/tests/conftest.py

@pytest.fixture
def mock_redis():
    return MockRedis()

root/tests/stuff/test.py

def test(mock_redis):
    print(mock_redis.get(stuff))

Another thing you can do is to write an installable plugin. In that case your helper can be written anywhere but it needs to define an entry point to be installed in your and other potential test frameworks. See this.

If you don't want to use fixtures, you could of course define a simple helper and just use the plain old import wherever it is needed.

root/tests/helper/redis.py

class MockRedis():
    # stuff

root/tests/stuff/test.py

from helper.redis import MockRedis

def test():
    print(MockRedis().get(stuff))

However, here you might have problems with the path since the module is not in a child folder of the test. You should be able to overcome this (not tested) by adding an __init__.py to your helper

root/tests/helper/init.py

from .redis import MockRedis

Or simply adding the helper module to your PYTHONPATH.

Answer from birkett on Stack Overflow
🌐
pytest
docs.pytest.org › en › stable › how-to › writing_plugins.html
Writing plugins - pytest documentation
Before a conftest.py file is loaded, load conftest.py files in all of its parent directories. After a conftest.py file is loaded, recursively load all plugins specified in its pytest_plugins variable if present.
🌐
pytest
docs.pytest.org › en › stable › how-to › plugins.html
How to install and use plugins - pytest documentation
The name pytest_plugins is reserved and should not be used as a name for a custom plugin module. If you want to find out which plugins are active in your environment you can type: ... and will get an extended test header which shows activated plugins and their names.
Top answer
1 of 6
713

Is this the correct use of conftest.py?

Yes it is. Fixtures are a potential and common use of conftest.py. The fixtures that you will define will be shared among all tests in your test suite. However, defining fixtures in the root conftest.py might be useless and it would slow down testing if such fixtures are not used by all tests.

Does it have other uses?

Yes it does.

  • Fixtures: Define fixtures for static data used by tests. This data can be accessed by all tests in the suite unless specified otherwise. This could be data as well as helpers of modules which will be passed to all tests.

  • External plugin loading: conftest.py is used to import external plugins or modules. By defining the following global variable, pytest will load the module and make it available for its test. Plugins are generally files defined in your project or other modules which might be needed in your tests. You can also load a set of predefined plugins as explained here.

    pytest_plugins = "someapp.someplugin"

  • Hooks: You can specify hooks such as setup and teardown methods and much more to improve your tests. For a set of available hooks, read Hooks link. Example:

      def pytest_runtest_setup(item):
           """ called before ``pytest_runtest_call(item). """
           #do some stuff`
    
  • Test root path: This is a bit of a hidden feature. By defining conftest.py in your root path, you will have pytest recognizing your application modules without specifying PYTHONPATH. In the background, py.test modifies your sys.path by including all submodules which are found from the root path.

Can I have more than one conftest.py file?

Yes you can and it is strongly recommended if your test structure is somewhat complex. conftest.py files have directory scope. Therefore, creating targeted fixtures and helpers is good practice.

When would I want to do that? Examples will be appreciated.

Several cases could fit:

Creating a set of tools or hooks for a particular group of tests.

root/mod/conftest.py

def pytest_runtest_setup(item):
    print("I am mod")
    #do some stuff


test root/mod2/test.py will NOT produce "I am mod"

Loading a set of fixtures for some tests but not for others.

root/mod/conftest.py

@pytest.fixture()
def fixture():
    return "some stuff"

root/mod2/conftest.py

@pytest.fixture()
def fixture():
    return "some other stuff"

root/mod2/test.py

def test(fixture):
    print(fixture)

Will print "some other stuff".

Overriding hooks inherited from the root conftest.py.

root/mod/conftest.py

def pytest_runtest_setup(item):
    print("I am mod")
    #do some stuff

root/conftest.py

def pytest_runtest_setup(item):
    print("I am root")
    #do some stuff

By running any test inside root/mod, only "I am mod" is printed.

You can read more about conftest.py here.

EDIT:

What if I need plain-old helper functions to be called from a number of tests in different modules - will they be available to me if I put them in a conftest.py? Or should I simply put them in a helpers.py module and import and use it in my test modules?

You can use conftest.py to define your helpers. However, you should follow common practice. Helpers can be used as fixtures at least in pytest. For example in my tests I have a mock redis helper which I inject into my tests this way.

root/helper/redis/redis.py

@pytest.fixture
def mock_redis():
    return MockRedis()

root/tests/stuff/conftest.py

pytest_plugin="helper.redis.redis"

root/tests/stuff/test.py

def test(mock_redis):
    print(mock_redis.get('stuff'))

This will be a test module that you can freely import in your tests. NOTE that you could potentially name redis.py as conftest.py if your module redis contains more tests. However, that practice is discouraged because of ambiguity.

If you want to use conftest.py, you can simply put that helper in your root conftest.py and inject it when needed.

root/tests/conftest.py

@pytest.fixture
def mock_redis():
    return MockRedis()

root/tests/stuff/test.py

def test(mock_redis):
    print(mock_redis.get(stuff))

Another thing you can do is to write an installable plugin. In that case your helper can be written anywhere but it needs to define an entry point to be installed in your and other potential test frameworks. See this.

If you don't want to use fixtures, you could of course define a simple helper and just use the plain old import wherever it is needed.

root/tests/helper/redis.py

class MockRedis():
    # stuff

root/tests/stuff/test.py

from helper.redis import MockRedis

def test():
    print(MockRedis().get(stuff))

However, here you might have problems with the path since the module is not in a child folder of the test. You should be able to overcome this (not tested) by adding an __init__.py to your helper

root/tests/helper/init.py

from .redis import MockRedis

Or simply adding the helper module to your PYTHONPATH.

2 of 6
25

Update Pytest 7.2 (2023 - March)

Adding this answer because there are some comment regarding missing information in the docs, which I guess was back when this question was first asked, but now is very well explained and documented.

From conftest.py: sharing fixtures across multiple files till the bottom of the page (and actually anything related to fixture or setting up pytest can be applied to the conftest.py) is related to conftest.py

Therefore, by quickly scanning the docs these are the main functionality (but not inclusive) :

  • Serve fixtures to tests (no matter the fixture scope)
  • Modularize the available fixture for each conftest.py in a Tree like hierarchy
  • Scope: sharing fixtures across classes, modules, packages or session
  • Child conftest.py can override parent conftest.py (but not the opposite) See this
  • Serve fixtures from a third-party plugins
  • Loading and Sharing test data across multiple tests
  • Using fixtures from other projects
  • Serve and share Hooks

Now on the accepted answer, it says Test root path: : This is a bit of a hidden feature. By defining ... but as for now, the best way to do this is instead add pythonpath to a pytest.ini on the root of your project (the actual project root, not project/tests ) see: pythonpath and does all for you and is more powerfull

Which looks like

[pytest]
pythonpath = src1 src2

Lastly, here I drop one of the many graphs that are in the pytest docs about The boundaries of the scopes can be visualized like this:

🌐
Readthedocs
happytest.readthedocs.io › en › latest › writing_plugins
Writing plugins — pytest documentation - Read the Docs
Local conftest.py plugins contain directory-specific hook implementations. Hook Session and test running activities will invoke all hooks defined in conftest.py files closer to the root of the filesystem. Example of implementing the pytest_runtest_setup hook so that is called for tests in the a sub directory but not for other directories:
🌐
pytest
docs.pytest.org › en › 6.2.x › writing_plugins.html
Writing plugins — pytest documentation
Local conftest.py plugins contain directory-specific hook implementations. Hook Session and test running activities will invoke all hooks defined in conftest.py files closer to the root of the filesystem. Example of implementing the pytest_runtest_setup hook so that is called for tests in the a sub directory but not for other directories:
🌐
GitHub
github.com › dbt-labs › dbt-utils › issues › 627
Defining 'pytest_plugins' in a non-top-level conftest is no longer supported · Issue #627 · dbt-labs/dbt-utils
August 1, 2022 - ==============================...________________________________________________________ Defining 'pytest_plugins' in a non-top-level conftest is no longer supported: It affects the entire test suite instead of just below the ...
Author   tekumara
🌐
pytest
docs.pytest.org › en › 7.1.x › how-to › plugins.html
How to install and use plugins — pytest documentation
The name pytest_plugins is reserved and should not be used as a name for a custom plugin module. If you want to find out which plugins are active in your environment you can type: ... and will get an extended test header which shows activated plugins and their names.
🌐
GitHub
github.com › pytest-dev › pytest › issues › 4039
If I can't put pytest_plugins in my conftest.py, where do I put it? · Issue #4039 · pytest-dev/pytest
September 26, 2018 - /home/njs/pytest-trio/pytest_trio/_tests/conftest.py:0: RemovedInPytest4Warning: Defining pytest_plugins in a non-top-level conftest is deprecated, because it affects the entire directory tree in a non-explicit way.
Author   njsmith
Find elsewhere
🌐
Pytest with Eric
pytest-with-eric.com › pytest-best-practices › pytest-conftest
Pytest Conftest With Best Practices And Real Examples | Pytest with Eric
October 25, 2022 - An example of using PyTest Plugins pytest-pikachu and pytest-progress . While there are other benefits of conftest for example - use in Hook Functions, it’s by far most used for Fixtures and Parameters.
🌐
pytest
docs.pytest.org › en › 6.2.x › plugins.html
Installing and Using plugins — pytest documentation
The name pytest_plugins is reserved and should not be used as a name for a custom plugin module. If you want to find out which plugins are active in your environment you can type: ... and will get an extended test header which shows activated plugins and their names.
🌐
pytest
docs.pytest.org › en › 6.2.x › explanation › fixtures.html
pytest fixtures: explicit, modular, scalable — pytest documentation
In case you want to use fixtures from a project that does not use entry points, you can define pytest_plugins in your top conftest.py file to register that module as a plugin.
🌐
GitHub
github.com › pytest-dev › pytest › issues › 13030
Should warn when using `pytest_plugins` in a test file (since it's also not the root conftest.py) · Issue #13030 · pytest-dev/pytest
December 5, 2024 - Moreover, since there's now a warning/error when using pytest_plugins in non-root conftest.py, the lack of a warning when using pytest_plugins in test files implies that using pytest_plugins in test files doesn't have the same problems.
Author   ryangalamb
🌐
pytest
pytest.org › en › 4.6.x › plugins.html
Installing and Using plugins — pytest documentation
The name pytest_plugins is reserved and should not be used as a name for a custom plugin module. If you want to find out which plugins are active in your environment you can type: ... and will get an extended test header which shows activated plugins and their names.
🌐
pytest
docs.pytest.org › en › stable › how-to › fixtures.html
How to use fixtures - pytest documentation
In case you want to use fixtures from a project that does not use entry points, you can define pytest_plugins in your top conftest.py file to register that module as a plugin.
🌐
Readthedocs
exhale.readthedocs.io › en › latest › testing › conftest.html
Testing Conftest Module — Exhale: Automatic C++ Library API Generation
testing.conftest.pytest_plugins = ['sphinx.testing.fixtures', 'testing.fixtures'] · Signals to pytest which plugins are needed for all tests. testing.conftest.pytest_configure(config)[source] · Register @pytest.mark.exhale with PyTest. testing.conftest.pytest_runtest_setup(item)[source] ...
🌐
GitHub
gist.github.com › peterhurford › 09f7dcda0ab04b95c026c60fa49c2a68
How to modularize your py.test fixtures · GitHub
./ ├── src ├── tests │ ├── conftest.py │ ├── fixtures │ │ ├── my_fixture.py · edit: I noticed, that I was executing pytest from tests instead of root. Fixed the discovery path and shortened string manipulation. Thanks a lot man.. this work like a charm for me.. ... You can simply create "local pytest plugins" which can be nothing more than Python files with fixtures, e.g.
🌐
pytest
docs.pytest.org › en › 2.0.3 › plugins.html
Working with plugins and conftest files — pytest v2.0.3 documentation
It will also print local plugins aka conftest.py files when they are loaded. You can prevent plugins from loading or unregister them: ... This means that any subsequent try to activate/load the named plugin will it already existing. See Finding out which plugins are active for how to obtain the name of a plugin. You can find the source code for the following plugins in the pytest repository.
🌐
pytest
docs.pytest.org › en › stable › reference › fixtures.html
Fixtures reference - pytest documentation
You can also use the conftest.py file to implement local per-directory plugins.
🌐
PyPI
pypi.org › project › pytest-plugins
pytest-plugins · PyPI
An advanced pytest plugin designed for Python projects, offering robust features and utilities to enhance the testing workflow. It includes improved conftest.py fixtures, automated test result reporting, detailed logging, and seamless integration ...
      » pip install pytest-plugins
    
Published   Apr 05, 2026
Version   3.0.1