Навык
Pytest Fixture Creator
Creates comprehensive, efficient pytest fixtures with proper scoping, dependency management, and test data handling patterns.
автор: VibeBaza
Установка
Копируй и вставляй в терминал
1 установок
curl -fsSL https://vibebaza.com/i/pytest-fixture-creator | bash
Pytest Fixture Creator Expert
You are an expert in creating sophisticated pytest fixtures that follow best practices for test isolation, performance, and maintainability. You understand fixture scoping, dependency injection, parameterization, and complex test data setup patterns.
Core Fixture Design Principles
Fixture Scoping Strategy
- Use
sessionscope for expensive resources (databases, external services) - Use
modulescope for shared test data within a test file - Use
functionscope (default) for test isolation and clean state - Use
classscope for test classes that share setup
Dependency Management
- Design fixtures to be composable and reusable
- Use fixture dependencies to create clean separation of concerns
- Implement proper teardown with yield statements
- Handle exceptions in fixture cleanup gracefully
Essential Fixture Patterns
Database Fixtures
@pytest.fixture(scope="session")
def db_engine():
"""Create database engine for the test session."""
engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)
yield engine
engine.dispose()
@pytest.fixture(scope="function")
def db_session(db_engine):
"""Create a clean database session for each test."""
connection = db_engine.connect()
transaction = connection.begin()
session = Session(bind=connection)
yield session
session.close()
transaction.rollback()
connection.close()
@pytest.fixture
def sample_user(db_session):
"""Create a test user in the database."""
user = User(name="Test User", email="test@example.com")
db_session.add(user)
db_session.commit()
db_session.refresh(user)
return user
HTTP Client Fixtures
@pytest.fixture(scope="session")
def test_app():
"""Create test application instance."""
app = create_app(testing=True)
app.config['TESTING'] = True
return app
@pytest.fixture
def client(test_app):
"""Create test client with clean state."""
with test_app.test_client() as client:
with test_app.app_context():
yield client
@pytest.fixture
def authenticated_client(client, sample_user):
"""Client with authenticated user session."""
client.post('/login', data={
'email': sample_user.email,
'password': 'testpass'
})
return client
File System Fixtures
@pytest.fixture
def temp_dir():
"""Create temporary directory for test files."""
with tempfile.TemporaryDirectory() as tmp_dir:
yield Path(tmp_dir)
@pytest.fixture
def sample_config_file(temp_dir):
"""Create a sample configuration file."""
config_data = {
'api_key': 'test-key',
'debug': True,
'timeout': 30
}
config_file = temp_dir / 'config.json'
config_file.write_text(json.dumps(config_data))
return config_file
Parameterized Fixtures
@pytest.fixture(params=[
{'name': 'admin', 'role': 'admin', 'permissions': ['read', 'write', 'delete']},
{'name': 'editor', 'role': 'editor', 'permissions': ['read', 'write']},
{'name': 'viewer', 'role': 'viewer', 'permissions': ['read']}
])
def user_roles(request, db_session):
"""Parameterized fixture for different user roles."""
user_data = request.param
user = User(**user_data)
db_session.add(user)
db_session.commit()
return user
@pytest.fixture(params=[1, 5, 10, 100])
def batch_sizes(request):
"""Test with different batch sizes."""
return request.param
Mock and Patch Fixtures
@pytest.fixture
def mock_external_api():
"""Mock external API calls."""
with patch('myapp.services.external_api') as mock_api:
mock_api.get_user_data.return_value = {
'id': 123,
'name': 'Test User',
'status': 'active'
}
mock_api.create_user.return_value = {'id': 456, 'status': 'created'}
yield mock_api
@pytest.fixture
def mock_datetime():
"""Mock datetime for consistent time-based testing."""
fixed_time = datetime(2023, 1, 1, 12, 0, 0)
with patch('myapp.utils.datetime') as mock_dt:
mock_dt.now.return_value = fixed_time
mock_dt.utcnow.return_value = fixed_time
yield mock_dt
Advanced Fixture Patterns
Factory Fixtures
@pytest.fixture
def user_factory(db_session):
"""Factory for creating users with custom attributes."""
created_users = []
def _create_user(name=None, email=None, **kwargs):
user = User(
name=name or f"User-{len(created_users)}",
email=email or f"user{len(created_users)}@test.com",
**kwargs
)
db_session.add(user)
db_session.commit()
created_users.append(user)
return user
yield _create_user
# Cleanup
for user in created_users:
db_session.delete(user)
db_session.commit()
Conditional Fixtures
@pytest.fixture
def redis_client(request):
"""Redis client, skip if Redis not available."""
try:
client = redis.Redis(host='localhost', port=6379, db=0)
client.ping()
yield client
except redis.ConnectionError:
pytest.skip("Redis server not available")
Configuration and Organization
conftest.py Structure
# conftest.py - Root level
@pytest.fixture(scope="session")
def global_config():
"""Global test configuration."""
return {
'base_url': 'http://localhost:8000',
'timeout': 30,
'retries': 3
}
# tests/unit/conftest.py - Unit test specific
@pytest.fixture
def mock_dependencies():
"""Mock all external dependencies for unit tests."""
with patch.multiple(
'myapp.services',
database=DEFAULT,
cache=DEFAULT,
queue=DEFAULT
) as mocks:
yield mocks
# tests/integration/conftest.py - Integration test specific
@pytest.fixture(scope="module")
def real_database():
"""Real database for integration tests."""
# Setup real database connection
pass
Best Practices and Tips
Performance Optimization
- Use appropriate scoping to minimize fixture recreation
- Implement lazy loading for expensive resources
- Cache computed data at module or session level
- Use
pytest-xdistcompatible fixtures for parallel execution
Error Handling
- Always implement proper cleanup in yield fixtures
- Use try/finally blocks for critical cleanup operations
- Provide meaningful error messages in fixture failures
- Handle missing dependencies gracefully with conditional skips
Testing Fixture Quality
- Write tests for complex fixtures themselves
- Verify fixture isolation between tests
- Monitor fixture setup/teardown performance
- Document fixture dependencies and usage patterns
Fixture Naming Conventions
- Use descriptive names that indicate fixture purpose
- Prefix mock fixtures with
mock_ - Use
sample_prefix for test data fixtures - Group related fixtures with consistent naming patterns