Explain Codes LogoExplain Codes Logo

In pytest, what is the use of conftest.py files?

python
fixture-engineering
test-preparation
best-practices
Anton ShumikhinbyAnton Shumikhin·Feb 24, 2025
TLDR

The file conftest.py acts like an orchestration tool in the pytest framework. Its key role is to define 'fixtures' that can be used across multiple test files to keep the code DRY (Don't Repeat Yourself) and maintain cleanliness. It also provides scope-based accessibility by allowing fixtures to behave differently based on where they are being called from.

Example:

# Inside the conftest.py file @pytest.fixture(scope="session") def db_connection(): # Creating an abstract factory pattern for database connections since it's so 'in' right now return setup_db_connection() # Inside the test_xyz.py file def test_query(db_connection): # Sending SQL to its home assert db_connection.run_query("SELECT 1") == 1

What can conftest.py do for you?

Granularity via fixture scopes

conftest.py shines when it comes to test environment setup. Roots fixtures — defined in the 'highest' conftest.py — cascade down to all subdirectories. However, by having multiple conftest.py files, you can define behavior at a directory level, providing scoped fixtures to the required tests.

Plugin loading

conftest.py can serve as a plugin loader. This gives you an easy way to extend the functionality of pytest by importing external plugins, aiding you in creating a truly customizable test suite.

Manipulating test behaviors via hooks

pytest provides a way to access and modify its internal operations using hook functions. conftest.py is where you can define these hooks to modify pytest's default behaviors, endowing you with control of the test setup, management, and teardown.

Make it work for you

Custom test manipulations

The hook functions in conftest.py are not mere spectators, they participate in the action. You can use them to manipulate how and when tests run — such as altering the test selection process, modifying test items pre-execution, or even skipping certain tests under specific conditions.

Visualizing fixture scopes

Understanding conftest.py can be made easier by visualizing tests with fixture scopes mapped out like a network diagram. Specially if you are using pytest with a larger project structure, such a view can give an overview of the interconnections and make managing fixtures easier.

Conftest.py and pytest.ini

The use of conftest.py and pytest.ini in tandem results in total control over your test environment. Defining the root directory in pytest.ini guarantees consistent fixture discovery, keeping your test environment disciplined and ordered.

Lesser-known yet impactful aspects

Project structure based on test scope

Placing conftest.py files strategically throughout your directory structure, mirroring fixture scopes, allows for a more manageable test suite. This way, the tests that need specific fixtures have access to them, while others remain unaffected.

Test clarity vs. import hassles

While the use of conftest.py obviates the need for import clutter in test files, ensuring visibility into which tests use what fixtures is key for maintainability. Always look for the sweet spot!

Power and peril of hook functions

While hook functions allow unprecedented control over test execution, misuse can lead to unexpected side effects, reminiscent of those frustrating Heisenbugs.

Overriding fixtures: Friend or foe?

Creating fixtures at different scopes in conftest.py files can cause "fixture shadowing" where a local fixture overrides a parent fixture. It's a master of disguise, so keep an eye out!