add new
Some checks failed
K8S Fission Deployment / Deployment fission functions (push) Failing after 12s
Some checks failed
K8S Fission Deployment / Deployment fission functions (push) Failing after 12s
This commit is contained in:
296
.agents/skills/pytest/references/fixtures.md
Normal file
296
.agents/skills/pytest/references/fixtures.md
Normal file
@@ -0,0 +1,296 @@
|
||||
# Fixtures
|
||||
|
||||
## Table of Contents
|
||||
- [Basic Fixtures](#basic-fixtures)
|
||||
- [Fixture Scopes](#fixture-scopes)
|
||||
- [Fixture Parameters](#fixture-parameters)
|
||||
- [Conftest.py](#conftestpy)
|
||||
- [Built-in Fixtures](#built-in-fixtures)
|
||||
|
||||
## Basic Fixtures
|
||||
|
||||
### Simple Fixture
|
||||
|
||||
```python
|
||||
import pytest
|
||||
|
||||
@pytest.fixture
|
||||
def user_data():
|
||||
"""Return sample user data."""
|
||||
return {
|
||||
"name": "John Doe",
|
||||
"email": "john@example.com",
|
||||
"age": 30,
|
||||
}
|
||||
|
||||
def test_user_name(user_data):
|
||||
assert user_data["name"] == "John Doe"
|
||||
|
||||
def test_user_email(user_data):
|
||||
assert "@" in user_data["email"]
|
||||
```
|
||||
|
||||
### Fixture with Setup and Teardown
|
||||
|
||||
```python
|
||||
@pytest.fixture
|
||||
def database():
|
||||
"""Setup database, yield, then cleanup."""
|
||||
# Setup
|
||||
db = create_database()
|
||||
db.connect()
|
||||
|
||||
yield db # Test runs here
|
||||
|
||||
# Teardown
|
||||
db.clear()
|
||||
db.disconnect()
|
||||
|
||||
def test_insert(database):
|
||||
database.insert({"id": 1, "name": "Test"})
|
||||
assert database.count() == 1
|
||||
```
|
||||
|
||||
### Fixture Returning Factory
|
||||
|
||||
```python
|
||||
@pytest.fixture
|
||||
def make_user():
|
||||
"""Return a factory function for creating users."""
|
||||
created_users = []
|
||||
|
||||
def _make_user(name: str, email: str = None):
|
||||
user = User(name=name, email=email or f"{name}@example.com")
|
||||
created_users.append(user)
|
||||
return user
|
||||
|
||||
yield _make_user
|
||||
|
||||
# Cleanup all created users
|
||||
for user in created_users:
|
||||
user.delete()
|
||||
|
||||
def test_multiple_users(make_user):
|
||||
user1 = make_user("Alice")
|
||||
user2 = make_user("Bob")
|
||||
assert user1.name != user2.name
|
||||
```
|
||||
|
||||
## Fixture Scopes
|
||||
|
||||
```python
|
||||
# Function scope (default) - runs for each test
|
||||
@pytest.fixture(scope="function")
|
||||
def fresh_data():
|
||||
return {"count": 0}
|
||||
|
||||
# Class scope - runs once per test class
|
||||
@pytest.fixture(scope="class")
|
||||
def class_resource():
|
||||
return ExpensiveResource()
|
||||
|
||||
# Module scope - runs once per test module
|
||||
@pytest.fixture(scope="module")
|
||||
def module_connection():
|
||||
conn = create_connection()
|
||||
yield conn
|
||||
conn.close()
|
||||
|
||||
# Session scope - runs once per test session
|
||||
@pytest.fixture(scope="session")
|
||||
def session_config():
|
||||
return load_config()
|
||||
```
|
||||
|
||||
### Scope Hierarchy
|
||||
|
||||
```
|
||||
session (once per test run)
|
||||
└── package (once per test package)
|
||||
└── module (once per test file)
|
||||
└── class (once per test class)
|
||||
└── function (once per test function)
|
||||
```
|
||||
|
||||
## Fixture Parameters
|
||||
|
||||
### Parametrized Fixtures
|
||||
|
||||
```python
|
||||
@pytest.fixture(params=["sqlite", "postgresql", "mysql"])
|
||||
def database_type(request):
|
||||
"""Run tests with each database type."""
|
||||
return request.param
|
||||
|
||||
def test_connection(database_type):
|
||||
# This test runs 3 times, once for each database
|
||||
db = create_database(database_type)
|
||||
assert db.connect()
|
||||
```
|
||||
|
||||
### Fixture with IDs
|
||||
|
||||
```python
|
||||
@pytest.fixture(params=[
|
||||
pytest.param({"admin": True}, id="admin"),
|
||||
pytest.param({"admin": False}, id="regular"),
|
||||
])
|
||||
def user_config(request):
|
||||
return request.param
|
||||
|
||||
# Test output shows: test_permissions[admin], test_permissions[regular]
|
||||
```
|
||||
|
||||
### Indirect Parametrization
|
||||
|
||||
```python
|
||||
@pytest.fixture
|
||||
def user(request):
|
||||
"""Create user based on parameter."""
|
||||
role = request.param
|
||||
return User(role=role)
|
||||
|
||||
@pytest.mark.parametrize("user", ["admin", "editor", "viewer"], indirect=True)
|
||||
def test_user_access(user):
|
||||
# user fixture receives each role as request.param
|
||||
assert user.role in ["admin", "editor", "viewer"]
|
||||
```
|
||||
|
||||
## Conftest.py
|
||||
|
||||
### tests/conftest.py
|
||||
|
||||
```python
|
||||
"""Shared fixtures for all tests."""
|
||||
import pytest
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
# Session-scoped database engine
|
||||
@pytest.fixture(scope="session")
|
||||
def engine():
|
||||
return create_engine("sqlite:///:memory:")
|
||||
|
||||
# Function-scoped session with transaction rollback
|
||||
@pytest.fixture(scope="function")
|
||||
def db_session(engine):
|
||||
connection = engine.connect()
|
||||
transaction = connection.begin()
|
||||
Session = sessionmaker(bind=connection)
|
||||
session = Session()
|
||||
|
||||
yield session
|
||||
|
||||
session.close()
|
||||
transaction.rollback()
|
||||
connection.close()
|
||||
|
||||
# Shared test data
|
||||
@pytest.fixture
|
||||
def sample_products():
|
||||
return [
|
||||
{"name": "Widget", "price": 9.99},
|
||||
{"name": "Gadget", "price": 19.99},
|
||||
{"name": "Gizmo", "price": 29.99},
|
||||
]
|
||||
```
|
||||
|
||||
### Nested Conftest Files
|
||||
|
||||
```
|
||||
tests/
|
||||
├── conftest.py # Available to all tests
|
||||
├── unit/
|
||||
│ ├── conftest.py # Available to unit tests only
|
||||
│ └── test_models.py
|
||||
└── integration/
|
||||
├── conftest.py # Available to integration tests only
|
||||
└── test_api.py
|
||||
```
|
||||
|
||||
## Built-in Fixtures
|
||||
|
||||
### tmp_path / tmp_path_factory
|
||||
|
||||
```python
|
||||
def test_create_file(tmp_path):
|
||||
"""tmp_path provides unique temporary directory."""
|
||||
file = tmp_path / "test.txt"
|
||||
file.write_text("Hello, World!")
|
||||
assert file.read_text() == "Hello, World!"
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def session_temp_dir(tmp_path_factory):
|
||||
"""Create temp dir for entire session."""
|
||||
return tmp_path_factory.mktemp("session_data")
|
||||
```
|
||||
|
||||
### capsys / capfd
|
||||
|
||||
```python
|
||||
def test_print_output(capsys):
|
||||
"""Capture stdout/stderr."""
|
||||
print("Hello")
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == "Hello\n"
|
||||
|
||||
def test_file_descriptor_output(capfd):
|
||||
"""Capture at file descriptor level."""
|
||||
import os
|
||||
os.system("echo 'Hello'")
|
||||
captured = capfd.readouterr()
|
||||
assert "Hello" in captured.out
|
||||
```
|
||||
|
||||
### monkeypatch
|
||||
|
||||
```python
|
||||
def test_env_variable(monkeypatch):
|
||||
"""Modify environment temporarily."""
|
||||
monkeypatch.setenv("API_KEY", "test-key")
|
||||
assert os.environ["API_KEY"] == "test-key"
|
||||
|
||||
def test_module_attribute(monkeypatch):
|
||||
"""Modify module attribute temporarily."""
|
||||
monkeypatch.setattr("module.CONFIG", {"debug": True})
|
||||
assert module.CONFIG["debug"] is True
|
||||
|
||||
def test_dict_item(monkeypatch):
|
||||
"""Modify dictionary temporarily."""
|
||||
monkeypatch.setitem(app.settings, "DEBUG", True)
|
||||
```
|
||||
|
||||
### request
|
||||
|
||||
```python
|
||||
@pytest.fixture
|
||||
def resource(request):
|
||||
"""Access test context."""
|
||||
print(f"Running: {request.node.name}")
|
||||
print(f"Module: {request.module.__name__}")
|
||||
print(f"Function: {request.function.__name__}")
|
||||
|
||||
# Access fixture parameters
|
||||
if hasattr(request, "param"):
|
||||
return create_resource(request.param)
|
||||
|
||||
return create_default_resource()
|
||||
```
|
||||
|
||||
### Autouse Fixtures
|
||||
|
||||
```python
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_logging():
|
||||
"""Automatically runs for every test."""
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
yield
|
||||
logging.shutdown()
|
||||
|
||||
@pytest.fixture(autouse=True, scope="session")
|
||||
def global_setup():
|
||||
"""Run once at session start."""
|
||||
initialize_system()
|
||||
yield
|
||||
cleanup_system()
|
||||
```
|
||||
Reference in New Issue
Block a user