major update
This commit is contained in:
99
tests/unit/test_fundamental_service.py
Normal file
99
tests/unit/test_fundamental_service.py
Normal file
@@ -0,0 +1,99 @@
|
||||
"""Unit tests for fundamental_service — unavailable_fields persistence."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
import pytest
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||
|
||||
from app.database import Base
|
||||
from app.models.ticker import Ticker
|
||||
from app.services import fundamental_service
|
||||
|
||||
# Use a dedicated engine so commit/refresh work without conflicting
|
||||
# with the conftest transactional session.
|
||||
_engine = create_async_engine("sqlite+aiosqlite://", echo=False)
|
||||
_session_factory = async_sessionmaker(_engine, class_=AsyncSession, expire_on_commit=False)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def _setup_tables():
|
||||
async with _engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
yield
|
||||
async with _engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.drop_all)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def session() -> AsyncSession:
|
||||
async with _session_factory() as s:
|
||||
yield s
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def ticker(session: AsyncSession) -> Ticker:
|
||||
"""Create a test ticker."""
|
||||
t = Ticker(symbol="AAPL")
|
||||
session.add(t)
|
||||
await session.commit()
|
||||
await session.refresh(t)
|
||||
return t
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_store_fundamental_persists_unavailable_fields(
|
||||
session: AsyncSession, ticker: Ticker
|
||||
):
|
||||
"""unavailable_fields dict is serialized to JSON and stored."""
|
||||
fields = {"pe_ratio": "requires paid plan", "revenue_growth": "requires paid plan"}
|
||||
|
||||
record = await fundamental_service.store_fundamental(
|
||||
session,
|
||||
symbol="AAPL",
|
||||
pe_ratio=None,
|
||||
revenue_growth=None,
|
||||
market_cap=1_000_000.0,
|
||||
unavailable_fields=fields,
|
||||
)
|
||||
|
||||
assert json.loads(record.unavailable_fields_json) == fields
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_store_fundamental_defaults_to_empty_dict(
|
||||
session: AsyncSession, ticker: Ticker
|
||||
):
|
||||
"""When unavailable_fields is not provided, column defaults to '{}'."""
|
||||
record = await fundamental_service.store_fundamental(
|
||||
session,
|
||||
symbol="AAPL",
|
||||
pe_ratio=25.0,
|
||||
)
|
||||
|
||||
assert json.loads(record.unavailable_fields_json) == {}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_store_fundamental_updates_unavailable_fields(
|
||||
session: AsyncSession, ticker: Ticker
|
||||
):
|
||||
"""Updating an existing record also updates unavailable_fields_json."""
|
||||
# First store
|
||||
await fundamental_service.store_fundamental(
|
||||
session,
|
||||
symbol="AAPL",
|
||||
pe_ratio=None,
|
||||
unavailable_fields={"pe_ratio": "requires paid plan"},
|
||||
)
|
||||
|
||||
# Second store — fields now available
|
||||
record = await fundamental_service.store_fundamental(
|
||||
session,
|
||||
symbol="AAPL",
|
||||
pe_ratio=25.0,
|
||||
unavailable_fields={},
|
||||
)
|
||||
|
||||
assert json.loads(record.unavailable_fields_json) == {}
|
||||
Reference in New Issue
Block a user