Files
bakery-ia/services/sales/tests/conftest.py
2025-08-12 18:17:30 +02:00

239 lines
6.4 KiB
Python

# services/sales/tests/conftest.py
"""
Pytest configuration and fixtures for Sales Service tests
"""
import pytest
import asyncio
from datetime import datetime, timezone
from decimal import Decimal
from typing import AsyncGenerator
from uuid import uuid4, UUID
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from sqlalchemy.pool import StaticPool
from fastapi.testclient import TestClient
from app.main import app
from app.core.config import settings
from app.core.database import Base, get_db
from app.models.sales import SalesData
from app.schemas.sales import SalesDataCreate
# Test database configuration
TEST_DATABASE_URL = "sqlite+aiosqlite:///:memory:"
@pytest.fixture(scope="session")
def event_loop():
"""Create event loop for the test session"""
loop = asyncio.new_event_loop()
yield loop
loop.close()
@pytest.fixture
async def test_engine():
"""Create test database engine"""
engine = create_async_engine(
TEST_DATABASE_URL,
poolclass=StaticPool,
connect_args={"check_same_thread": False}
)
# Create tables
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
yield engine
await engine.dispose()
@pytest.fixture
async def test_db_session(test_engine) -> AsyncGenerator[AsyncSession, None]:
"""Create test database session"""
async_session = async_sessionmaker(
test_engine, class_=AsyncSession, expire_on_commit=False
)
async with async_session() as session:
yield session
@pytest.fixture
def test_client():
"""Create test client"""
return TestClient(app)
@pytest.fixture
async def override_get_db(test_db_session):
"""Override get_db dependency for testing"""
async def _override_get_db():
yield test_db_session
app.dependency_overrides[get_db] = _override_get_db
yield
app.dependency_overrides.clear()
# Test data fixtures
@pytest.fixture
def sample_tenant_id() -> UUID:
"""Sample tenant ID for testing"""
return uuid4()
@pytest.fixture
def sample_sales_data(sample_tenant_id: UUID) -> SalesDataCreate:
"""Sample sales data for testing"""
return SalesDataCreate(
date=datetime.now(timezone.utc),
product_name="Pan Integral",
product_category="Panadería",
product_sku="PAN001",
quantity_sold=5,
unit_price=Decimal("2.50"),
revenue=Decimal("12.50"),
cost_of_goods=Decimal("6.25"),
discount_applied=Decimal("0"),
location_id="STORE_001",
sales_channel="in_store",
source="manual",
notes="Test sale",
weather_condition="sunny",
is_holiday=False,
is_weekend=False
)
@pytest.fixture
def sample_sales_records(sample_tenant_id: UUID) -> list[dict]:
"""Multiple sample sales records"""
base_date = datetime.now(timezone.utc)
return [
{
"tenant_id": sample_tenant_id,
"date": base_date,
"product_name": "Croissant",
"quantity_sold": 3,
"revenue": Decimal("7.50"),
"location_id": "STORE_001",
"source": "manual"
},
{
"tenant_id": sample_tenant_id,
"date": base_date,
"product_name": "Café Americano",
"quantity_sold": 2,
"revenue": Decimal("5.00"),
"location_id": "STORE_001",
"source": "pos"
},
{
"tenant_id": sample_tenant_id,
"date": base_date,
"product_name": "Bocadillo Jamón",
"quantity_sold": 1,
"revenue": Decimal("4.50"),
"location_id": "STORE_002",
"source": "manual"
}
]
@pytest.fixture
def sample_csv_data() -> str:
"""Sample CSV data for import testing"""
return """date,product,quantity,revenue,location
2024-01-15,Pan Integral,5,12.50,STORE_001
2024-01-15,Croissant,3,7.50,STORE_001
2024-01-15,Café Americano,2,5.00,STORE_002
2024-01-16,Pan de Molde,8,16.00,STORE_001
2024-01-16,Magdalenas,6,9.00,STORE_002"""
@pytest.fixture
def sample_json_data() -> str:
"""Sample JSON data for import testing"""
return """[
{
"date": "2024-01-15",
"product": "Pan Integral",
"quantity": 5,
"revenue": 12.50,
"location": "STORE_001"
},
{
"date": "2024-01-15",
"product": "Croissant",
"quantity": 3,
"revenue": 7.50,
"location": "STORE_001"
}
]"""
@pytest.fixture
async def populated_db(test_db_session: AsyncSession, sample_sales_records: list[dict]):
"""Database populated with test data"""
for record_data in sample_sales_records:
sales_record = SalesData(**record_data)
test_db_session.add(sales_record)
await test_db_session.commit()
yield test_db_session
# Mock fixtures for external dependencies
@pytest.fixture
def mock_messaging():
"""Mock messaging service"""
class MockMessaging:
def __init__(self):
self.published_events = []
async def publish_sales_created(self, data):
self.published_events.append(("sales_created", data))
return True
async def publish_data_imported(self, data):
self.published_events.append(("data_imported", data))
return True
return MockMessaging()
# Performance testing fixtures
@pytest.fixture
def large_csv_data() -> str:
"""Large CSV data for performance testing"""
headers = "date,product,quantity,revenue,location\n"
rows = []
for i in range(1000): # 1000 records
rows.append(f"2024-01-{(i % 30) + 1:02d},Producto_{i % 10},1,2.50,STORE_{i % 3 + 1:03d}")
return headers + "\n".join(rows)
@pytest.fixture
def performance_test_data(sample_tenant_id: UUID) -> list[dict]:
"""Large dataset for performance testing"""
records = []
base_date = datetime.now(timezone.utc)
for i in range(500): # 500 records
records.append({
"tenant_id": sample_tenant_id,
"date": base_date,
"product_name": f"Test Product {i % 20}",
"quantity_sold": (i % 10) + 1,
"revenue": Decimal(str(((i % 10) + 1) * 2.5)),
"location_id": f"STORE_{(i % 5) + 1:03d}",
"source": "test"
})
return records