fixes and refactor
This commit is contained in:
158
tests/test_mortality.py
Normal file
158
tests/test_mortality.py
Normal file
@@ -0,0 +1,158 @@
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
# Ensure required env vars for app import/config
|
||||
os.environ.setdefault("SECRET_KEY", "x" * 32)
|
||||
os.environ.setdefault("DATABASE_URL", "sqlite:////tmp/delphi_test.sqlite")
|
||||
|
||||
# Ensure repository root on sys.path for direct test runs
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from app.main import app # noqa: E402
|
||||
from app.auth.security import get_current_user # noqa: E402
|
||||
from tests.helpers import assert_http_error # noqa: E402
|
||||
from app.database.base import SessionLocal # noqa: E402
|
||||
from app.models.pensions import LifeTable, NumberTable # noqa: E402
|
||||
from app.services.mortality import ( # noqa: E402
|
||||
get_life_values,
|
||||
get_number_value,
|
||||
InvalidCodeError,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def client():
|
||||
# Override auth to bypass JWT for these tests
|
||||
class _User:
|
||||
def __init__(self):
|
||||
self.id = "test"
|
||||
self.username = "tester"
|
||||
self.is_admin = True
|
||||
self.is_active = True
|
||||
|
||||
app.dependency_overrides[get_current_user] = lambda: _User()
|
||||
|
||||
try:
|
||||
yield TestClient(app)
|
||||
finally:
|
||||
app.dependency_overrides.pop(get_current_user, None)
|
||||
|
||||
|
||||
def _seed_life_and_number():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
# Seed a life table row for age 65
|
||||
db.query(LifeTable).filter(LifeTable.age == 65).delete()
|
||||
lt = LifeTable(
|
||||
age=65,
|
||||
le_wm=14.5,
|
||||
na_wm=87000.0,
|
||||
le_af=20.1,
|
||||
na_af=92000.0,
|
||||
le_ha=18.2,
|
||||
na_ha=88000.0,
|
||||
)
|
||||
db.add(lt)
|
||||
|
||||
# Seed a number table row for month 305
|
||||
db.query(NumberTable).filter(NumberTable.month == 305).delete()
|
||||
nt = NumberTable(
|
||||
month=305,
|
||||
na_wm=80000.0,
|
||||
na_af=90000.0,
|
||||
na_ha=85000.0,
|
||||
)
|
||||
db.add(nt)
|
||||
|
||||
db.commit()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def test_service_helpers_success_invalid_and_not_found():
|
||||
_seed_life_and_number()
|
||||
db = SessionLocal()
|
||||
try:
|
||||
# Success cases
|
||||
res = get_life_values(db, age=65, sex="M", race="W")
|
||||
assert res and res["le"] == 14.5 and res["na"] == 87000.0
|
||||
res = get_life_values(db, age=65, sex="F", race="A")
|
||||
assert res and res["le"] == 20.1 and res["na"] == 92000.0
|
||||
res = get_life_values(db, age=65, sex="A", race="H")
|
||||
assert res and res["le"] == 18.2 and res["na"] == 88000.0
|
||||
|
||||
nres = get_number_value(db, month=305, sex="M", race="W")
|
||||
assert nres and nres["na"] == 80000.0
|
||||
nres = get_number_value(db, month=305, sex="F", race="A")
|
||||
assert nres and nres["na"] == 90000.0
|
||||
nres = get_number_value(db, month=305, sex="A", race="H")
|
||||
assert nres and nres["na"] == 85000.0
|
||||
|
||||
# Invalid codes
|
||||
with pytest.raises(InvalidCodeError):
|
||||
get_life_values(db, age=65, sex="X", race="W")
|
||||
with pytest.raises(InvalidCodeError):
|
||||
get_number_value(db, month=305, sex="M", race="Z")
|
||||
|
||||
# Not found
|
||||
assert get_life_values(db, age=9999, sex="M", race="W") is None
|
||||
assert get_number_value(db, month=99999, sex="M", race="W") is None
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def test_api_life_valid_invalid_not_found(client: TestClient):
|
||||
_seed_life_and_number()
|
||||
|
||||
# Valid lookups
|
||||
resp = client.get("/api/mortality/life/65", params={"sex": "M", "race": "W"})
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["le"] == 14.5 and data["na"] == 87000.0
|
||||
|
||||
resp = client.get("/api/mortality/life/65", params={"sex": "F", "race": "A"})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["le"] == 20.1
|
||||
|
||||
# Invalid code -> 400 wrapped error
|
||||
resp = client.get("/api/mortality/life/65", params={"sex": "X", "race": "W"})
|
||||
assert_http_error(resp, 400, "Invalid sex code")
|
||||
|
||||
# Not found -> 404 wrapped error
|
||||
resp = client.get("/api/mortality/life/9999", params={"sex": "M", "race": "W"})
|
||||
assert_http_error(resp, 404, "Age not found")
|
||||
|
||||
|
||||
def test_api_number_valid_invalid_not_found(client: TestClient):
|
||||
_seed_life_and_number()
|
||||
|
||||
# Valid lookup
|
||||
resp = client.get("/api/mortality/number/305", params={"sex": "M", "race": "W"})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["na"] == 80000.0
|
||||
|
||||
# Invalid code -> 400
|
||||
resp = client.get("/api/mortality/number/305", params={"sex": "M", "race": "Z"})
|
||||
assert_http_error(resp, 400, "Invalid race code")
|
||||
|
||||
# Not found -> 404
|
||||
resp = client.get("/api/mortality/number/99999", params={"sex": "M", "race": "W"})
|
||||
assert_http_error(resp, 404, "Month not found")
|
||||
|
||||
|
||||
def test_api_validation_negative_inputs(client: TestClient):
|
||||
# Negative age -> 422 validation envelope
|
||||
resp = client.get("/api/mortality/life/-1", params={"sex": "M", "race": "W"})
|
||||
from tests.helpers import assert_validation_error
|
||||
assert_validation_error(resp, "age")
|
||||
|
||||
# Negative month -> 422 validation envelope
|
||||
resp = client.get("/api/mortality/number/-5", params={"sex": "F", "race": "A"})
|
||||
assert_validation_error(resp, "month")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user