Lesson 7 · Pytest deep dive
pytest Tutorial #7: conftest.py & Sharing Fixtures
On testing real Python code with pytest. conftest.py: real shared fixtures, no imports required, plus autouse. Let's get into it. conftest.py is a special…
- CoursePytest deep dive
- Lesson7 of 18
- FormatJupyter notebook · 6 code cells
What you'll learn
Data
No separate download needed — the notebook creates or downloads everything it uses.
📓 Full notebook
Download .ipynbpytest Deep-Dive, Video 7: conftest.py and Fixture Sharing#
- Video seven of an eighteen-part series on testing real Python code with pytest.
- conftest.py: real shared fixtures, no imports required, plus autouse.
- Let's get into it.
Part 1: A New Helper - Running pytest Against Multiple Files#
import pytest, tempfile, os
def run_pytest_dir(files, args=None):
tmpdir = tempfile.mkdtemp()
for filename, content in files.items():
with open(os.path.join(tmpdir, filename), 'w') as f:
f.write(content)
result = pytest.main([tmpdir, *(args or [])])
return result
Part 2: A Basic conftest.py Fixture#
conftest_code = """
import pytest
@pytest.fixture
def sample_numbers():
return [3, 1, 4, 1, 5, 9]
"""
test_code = """
def test_sum(sample_numbers):
assert sum(sample_numbers) == 23
def test_length(sample_numbers):
assert len(sample_numbers) == 6
"""
exit_code = run_pytest_dir({'conftest.py': conftest_code, 'test_numbers.py': test_code}, ['-v', '--no-header'])
print(exit_code)
Part 3: One conftest.py, Multiple Test Files#
conftest_code = """
import pytest
@pytest.fixture
def sample_numbers():
return [3, 1, 4, 1, 5, 9]
"""
test_a_code = """
def test_max_value(sample_numbers):
assert max(sample_numbers) == 9
"""
test_b_code = """
def test_min_value(sample_numbers):
assert min(sample_numbers) == 1
"""
files = {
'conftest.py': conftest_code,
'test_a.py': test_a_code,
'test_b.py': test_b_code,
}
exit_code = run_pytest_dir(files, ['-v', '--no-header'])
print(exit_code)
Part 4: autouse - Fixtures That Run Without Being Requested#
conftest_code = """
import pytest
events = []
@pytest.fixture(autouse=True)
def track_every_test():
events.append('setup')
yield
events.append('teardown')
"""
test_code = """
from conftest import events
def test_one():
assert 'setup' in events
def test_two():
assert events.count('setup') >= 2
"""
exit_code = run_pytest_dir({'conftest.py': conftest_code, 'test_autouse.py': test_code}, ['-v', '--no-header'])
print(exit_code)
Part 5: A Local Fixture Overrides a conftest.py Fixture#
conftest_code = """
import pytest
@pytest.fixture
def environment_name():
return 'production'
"""
test_shared_code = """
def test_uses_shared_environment(environment_name):
assert environment_name == 'production'
"""
test_override_code = """
import pytest
@pytest.fixture
def environment_name():
return 'testing'
def test_uses_overridden_environment(environment_name):
assert environment_name == 'testing'
"""
files = {
'conftest.py': conftest_code,
'test_shared.py': test_shared_code,
'test_override.py': test_override_code,
}
exit_code = run_pytest_dir(files, ['-v', '--no-header'])
print(exit_code)
Part 6: A Real Pattern - a Shared Fake-Client Fixture#
conftest_code = """
import pytest
class FakeApiClient:
def __init__(self):
self.calls = []
def get(self, path):
self.calls.append(path)
return {'path': path, 'status': 'ok'}
@pytest.fixture
def api_client():
return FakeApiClient()
"""
test_users_code = """
def test_get_users(api_client):
response = api_client.get('/users')
assert response['status'] == 'ok'
assert api_client.calls == ['/users']
"""
test_orders_code = """
def test_get_orders(api_client):
response = api_client.get('/orders')
assert response['path'] == '/orders'
"""
files = {
'conftest.py': conftest_code,
'test_users.py': test_users_code,
'test_orders.py': test_orders_code,
}
exit_code = run_pytest_dir(files, ['-v', '--no-header'])
print(exit_code)
Wrap-Up: What You Learned#
- conftest.py is a special filename pytest automatically discovers; its fixtures need no import at all.
- One conftest.py fixture is available to every test file in the same directory, and any subdirectory.
- @pytest.fixture(autouse=True) runs a fixture for every test in scope without any test requesting it.
- A test file can define a fixture with the same name as one in conftest.py, overriding it locally.
- Overriding only affects the file that redefines it; every other file still uses the shared conftest version.
- A shared fake-client fixture in conftest.py avoids redefining the same setup across many test files.
- That wraps up conftest.py and fixture sharing. Next up: Fixture Scopes and Finalization.
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



