test: add 159 tests for all new modules

New test files (171 tests):
- test_routes_shorts.py (16) - short volume, FTD, interest, darkpool
- test_routes_fixed_income.py (34) - treasury, yield curve, SOFR, etc.
- test_routes_economy.py (44) - CPI, GDP, FRED search, Fed holdings
- test_routes_surveys.py (17) - Michigan, SLOOS, NFP, Empire State
- test_routes_regulators.py (20) - COT, SEC litigation, institutions
- test_finnhub_service_social.py (20) - social/reddit sentiment unit tests
- test_routes_sentiment_social.py (20) - social endpoints + composite

Updated:
- test_routes_sentiment.py - match new composite sentiment response shape

Total: 261 tests passing (was 102)
This commit is contained in:
Yaojia Wang
2026-03-19 22:12:27 +01:00
parent ea72497587
commit 27b131492f
8 changed files with 2098 additions and 5 deletions

View File

@@ -0,0 +1,189 @@
"""Tests for economy survey routes."""
from unittest.mock import patch, AsyncMock
import pytest
from httpx import AsyncClient, ASGITransport
from main import app
@pytest.fixture
async def client():
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://test") as c:
yield c
# --- Michigan Consumer Sentiment ---
@pytest.mark.asyncio
@patch("routes_surveys.surveys_service.get_michigan", new_callable=AsyncMock)
async def test_survey_michigan_happy_path(mock_fn, client):
mock_fn.return_value = [
{"date": "2026-03-01", "consumer_sentiment": 76.5, "inflation_expectation_1yr": 3.1}
]
resp = await client.get("/api/v1/economy/surveys/michigan")
assert resp.status_code == 200
data = resp.json()
assert data["success"] is True
assert data["data"][0]["consumer_sentiment"] == 76.5
@pytest.mark.asyncio
@patch("routes_surveys.surveys_service.get_michigan", new_callable=AsyncMock)
async def test_survey_michigan_empty(mock_fn, client):
mock_fn.return_value = []
resp = await client.get("/api/v1/economy/surveys/michigan")
assert resp.status_code == 200
assert resp.json()["data"] == []
@pytest.mark.asyncio
@patch("routes_surveys.surveys_service.get_michigan", new_callable=AsyncMock)
async def test_survey_michigan_service_error_returns_502(mock_fn, client):
mock_fn.side_effect = RuntimeError("FRED unavailable")
resp = await client.get("/api/v1/economy/surveys/michigan")
assert resp.status_code == 502
# --- SLOOS ---
@pytest.mark.asyncio
@patch("routes_surveys.surveys_service.get_sloos", new_callable=AsyncMock)
async def test_survey_sloos_happy_path(mock_fn, client):
mock_fn.return_value = [
{"date": "2026-01-01", "c_i_tightening_pct": 25.0, "consumer_tightening_pct": 10.0}
]
resp = await client.get("/api/v1/economy/surveys/sloos")
assert resp.status_code == 200
data = resp.json()
assert data["success"] is True
assert data["data"][0]["c_i_tightening_pct"] == 25.0
@pytest.mark.asyncio
@patch("routes_surveys.surveys_service.get_sloos", new_callable=AsyncMock)
async def test_survey_sloos_empty(mock_fn, client):
mock_fn.return_value = []
resp = await client.get("/api/v1/economy/surveys/sloos")
assert resp.status_code == 200
assert resp.json()["data"] == []
@pytest.mark.asyncio
@patch("routes_surveys.surveys_service.get_sloos", new_callable=AsyncMock)
async def test_survey_sloos_service_error_returns_502(mock_fn, client):
mock_fn.side_effect = RuntimeError("FRED down")
resp = await client.get("/api/v1/economy/surveys/sloos")
assert resp.status_code == 502
# --- Nonfarm Payrolls ---
@pytest.mark.asyncio
@patch("routes_surveys.surveys_service.get_nonfarm_payrolls", new_callable=AsyncMock)
async def test_survey_nfp_happy_path(mock_fn, client):
mock_fn.return_value = [
{"date": "2026-03-07", "value": 275000, "industry": "total_nonfarm"}
]
resp = await client.get("/api/v1/economy/surveys/nonfarm-payrolls")
assert resp.status_code == 200
data = resp.json()
assert data["success"] is True
assert data["data"][0]["value"] == 275000
@pytest.mark.asyncio
@patch("routes_surveys.surveys_service.get_nonfarm_payrolls", new_callable=AsyncMock)
async def test_survey_nfp_empty(mock_fn, client):
mock_fn.return_value = []
resp = await client.get("/api/v1/economy/surveys/nonfarm-payrolls")
assert resp.status_code == 200
assert resp.json()["data"] == []
@pytest.mark.asyncio
@patch("routes_surveys.surveys_service.get_nonfarm_payrolls", new_callable=AsyncMock)
async def test_survey_nfp_service_error_returns_502(mock_fn, client):
mock_fn.side_effect = RuntimeError("BLS unavailable")
resp = await client.get("/api/v1/economy/surveys/nonfarm-payrolls")
assert resp.status_code == 502
# --- Empire State Manufacturing ---
@pytest.mark.asyncio
@patch("routes_surveys.surveys_service.get_empire_state", new_callable=AsyncMock)
async def test_survey_empire_state_happy_path(mock_fn, client):
mock_fn.return_value = [
{"date": "2026-03-01", "general_business_conditions": -7.58}
]
resp = await client.get("/api/v1/economy/surveys/empire-state")
assert resp.status_code == 200
data = resp.json()
assert data["success"] is True
assert data["data"][0]["general_business_conditions"] == -7.58
@pytest.mark.asyncio
@patch("routes_surveys.surveys_service.get_empire_state", new_callable=AsyncMock)
async def test_survey_empire_state_empty(mock_fn, client):
mock_fn.return_value = []
resp = await client.get("/api/v1/economy/surveys/empire-state")
assert resp.status_code == 200
assert resp.json()["data"] == []
@pytest.mark.asyncio
@patch("routes_surveys.surveys_service.get_empire_state", new_callable=AsyncMock)
async def test_survey_empire_state_service_error_returns_502(mock_fn, client):
mock_fn.side_effect = RuntimeError("FRED connection error")
resp = await client.get("/api/v1/economy/surveys/empire-state")
assert resp.status_code == 502
# --- BLS Search ---
@pytest.mark.asyncio
@patch("routes_surveys.surveys_service.bls_search", new_callable=AsyncMock)
async def test_survey_bls_search_happy_path(mock_fn, client):
mock_fn.return_value = [
{"series_id": "CES0000000001", "series_title": "All employees, thousands, total nonfarm"},
{"series_id": "CES1000000001", "series_title": "All employees, thousands, mining and logging"},
]
resp = await client.get("/api/v1/economy/surveys/bls-search?query=nonfarm+payrolls")
assert resp.status_code == 200
data = resp.json()
assert data["success"] is True
assert len(data["data"]) == 2
assert data["data"][0]["series_id"] == "CES0000000001"
mock_fn.assert_called_once_with(query="nonfarm payrolls")
@pytest.mark.asyncio
async def test_survey_bls_search_missing_query(client):
resp = await client.get("/api/v1/economy/surveys/bls-search")
assert resp.status_code == 422
@pytest.mark.asyncio
@patch("routes_surveys.surveys_service.bls_search", new_callable=AsyncMock)
async def test_survey_bls_search_empty(mock_fn, client):
mock_fn.return_value = []
resp = await client.get("/api/v1/economy/surveys/bls-search?query=nothingtofind")
assert resp.status_code == 200
assert resp.json()["data"] == []
@pytest.mark.asyncio
@patch("routes_surveys.surveys_service.bls_search", new_callable=AsyncMock)
async def test_survey_bls_search_service_error_returns_502(mock_fn, client):
mock_fn.side_effect = RuntimeError("BLS API down")
resp = await client.get("/api/v1/economy/surveys/bls-search?query=wages")
assert resp.status_code == 502