Testing with pytest
Also Known As
pytest
Python testing
conftest
TL;DR
pytest is Python's dominant testing framework — its fixture system, parametrize decorator, and plugin ecosystem make it more powerful and less verbose than unittest.
Explanation
pytest discovers tests by naming convention (test_*.py, *_test.py), uses plain assert statements with introspective failure messages, and provides fixtures via dependency injection (function parameters). Key features: @pytest.fixture for reusable setup/teardown, @pytest.mark.parametrize for data-driven tests, conftest.py for shared fixtures, and marks for grouping tests. The plugin ecosystem (pytest-cov, pytest-mock, pytest-asyncio) covers virtually every testing need.
Common Misconception
✗ pytest fixtures are complicated — the dependency injection pattern (fixture as function parameter) is simpler than unittest setUp/tearDown once understood.
Why It Matters
pytest's failure messages show the actual vs expected values and the expression that failed — far more actionable than unittest's 'AssertionError: False is not True'.
Common Mistakes
- Not using fixtures for shared setup — copy-pasting setup code across tests instead of extracting a fixture.
- Fixtures with too wide a scope — session-scoped fixtures with mutable state bleed between tests.
- Not using parametrize for data-driven tests — writing the same test five times with different inputs.
- Not using conftest.py for shared fixtures — defining fixtures in every test file instead of once.
Code Examples
✗ Vulnerable
# unittest style — verbose:
import unittest
class TestUserService(unittest.TestCase):
def setUp(self):
self.db = create_test_db()
self.service = UserService(self.db)
def test_create_user_success(self):
result = self.service.create({'email': 'a@b.com', 'name': 'Alice'})
self.assertEqual(result['email'], 'a@b.com') # Less informative failure
✓ Fixed
# pytest style — concise, with fixtures:
import pytest
@pytest.fixture
def user_service():
db = create_test_db()
yield UserService(db)
db.rollback() # Teardown
@pytest.mark.parametrize('email,name', [
('alice@example.com', 'Alice'),
('bob@example.com', 'Bob'),
])
def test_create_user(user_service, email, name):
result = user_service.create({'email': email, 'name': name})
assert result['email'] == email # pytest shows actual vs expected on failure
References
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
15 Mar 2026
Edited
22 Mar 2026
Views
31
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
No pings yesterday
Amazonbot 8
Google 7
Perplexity 6
Unknown AI 2
ChatGPT 2
Ahrefs 1
Also referenced
How they use it
crawler 23
crawler_json 3
Related categories
⚡
DEV INTEL
Tools & Severity
🟡 Medium
⚙ Fix effort: Medium
⚡ Quick Fix
Use pytest fixtures for setup/teardown and parametrize for data-driven tests — it's simpler than unittest with less boilerplate; install pytest-cov for coverage and pytest-mock for mocking
📦 Applies To
python 3.6
web
cli
🔗 Prerequisites
🔍 Detection Hints
unittest.TestCase for all tests when pytest would be simpler; no fixtures for common setup; no parametrize for data-driven tests
Auto-detectable:
✓ Yes
pytest
coverage
pytest-mock
ruff
⚠ Related Problems
🤖 AI Agent
Confidence: Medium
False Positives: Medium
✗ Manual fix
Fix: Medium
Context: File
Tests: Update