Files
invest-copilot/src/backend/tests/conftest.py.bak
T

170 lines
4.4 KiB
Plaintext

"""Shared fixtures for all backend tests.
CRITICAL: The database mock must be injected into sys.modules BEFORE
any other imports that might trigger database.py to load. This is why
the mock is created at module level (lines 13-27) before any imports.
"""
import asyncio
import sys
import types
from unittest.mock import AsyncMock
import pytest
from httpx import AsyncClient, ASGITransport
# ── Mock database module (MUST be before any imports) ──────────────
_db_mock = AsyncMock()
_db_mock.execute_query = AsyncMock(return_value=[])
_db_mock.execute_command = AsyncMock(return_value=None)
_db_mock.execute_one = AsyncMock(return_value=None)
_db_mock.init_db = AsyncMock()
_db_mock.close_db = AsyncMock()
_db_mock.get_connection = AsyncMock()
_db_mock.release_connection = AsyncMock()
_db_mod = types.ModuleType("database")
_db_mod.execute_query = _db_mock.execute_query
_db_mod.execute_command = _db_mock.execute_command
_db_mod.execute_one = _db_mock.execute_one
_db_mod.init_db = _db_mock.init_db
_db_mod.close_db = _db_mock.close_db
_db_mod.get_connection = _db_mock.get_connection
_db_mod.release_connection = _db_mock.release_connection
sys.modules["database"] = _db_mod
# ────────────────────────────────────────────────────────────────────
@pytest.fixture
def event_loop():
"""Create a fresh event loop for each test."""
loop = asyncio.new_event_loop()
yield loop
loop.close()
@pytest.fixture
def mock_db():
"""Return the shared mock database object."""
return _db_mock
@pytest.fixture
def mock_user_data():
"""Valid user registration data."""
return {
"email": "test@example.com",
"password": "SecurePass123!",
"name": "Test User",
}
@pytest.fixture
def mock_watchlist_data():
"""Valid watchlist creation data."""
return {
"name": "My Watchlist",
"description": "Test watchlist for AAPL",
}
@pytest.fixture
def mock_watchlist_item():
"""Valid watchlist item data."""
return {
"ticker": "AAPL",
"type": "stock",
"notes": "Apple Inc.",
}
@pytest.fixture
def mock_stock_profile():
"""Mock stock profile data."""
return {
"ticker": "AAPL",
"name": "Apple Inc.",
"sector": "Technology",
"industry": "Consumer Electronics",
"pe_ratio": 32.5,
"market_cap": 3_000_000_000_000,
"price": 180.0,
"change_pct": 2.5,
"volume": 50_000_000,
"description": "Apple Inc. designs, manufactures, and sells consumer electronics.",
}
@pytest.fixture
def mock_price_data():
"""Mock price history data."""
return [
{
"date": "2024-01-02",
"open": 185.0,
"high": 187.0,
"low": 183.0,
"close": 186.5,
"volume": 50_000_000,
},
{
"date": "2024-01-03",
"open": 186.5,
"high": 189.0,
"low": 185.0,
"close": 187.0,
"volume": 52_000_000,
},
]
@pytest.fixture
def mock_search_results():
"""Mock search results."""
return [
{
"ticker": "AAPL",
"name": "Apple Inc.",
"sector": "Technology",
"exchange": "NASDAQ",
},
{
"ticker": "AAPL34.SA",
"name": "Apple Inc. BDR",
"sector": "Technology",
"exchange": "BVMF",
},
]
@pytest.fixture
def test_user(mock_db):
"""Create a test user with a valid JWT token."""
from services.auth import create_access_token
token = create_access_token(
data={"sub": "0000-01", "email": "test@example.com"},
)
return {
"token": token,
"user_id": "0000-01",
"email": "test@example.com",
"name": "Test User",
}
@pytest.fixture
def app(mock_db):
"""Create a FastAPI app with mocked database."""
# At this point, sys.modules["database"] is already patched (module-level).
# Import main — it will pick up our mock.
import main
return main.app
@pytest.fixture
async def client(app, mock_db):
"""Create an async test client with mocked database."""
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://test") as ac:
yield ac