AdminAnalytics/tests/test_dashboard_queries.py
2026-03-30 19:29:33 -04:00

168 lines
5.7 KiB
Python

"""Tests for dashboard query functions."""
from admin_analytics.config import UD_UNITID
from admin_analytics.dashboard.queries import (
query_admin_cost_ratio,
query_expense_breakdown,
query_admin_per_student,
query_admin_faculty_ratio,
query_top_earners,
query_comp_by_role,
query_comp_vs_cpi,
query_staff_composition,
query_student_staff_ratios,
query_growth_index,
query_admin_headcount,
query_headcount_summary,
)
def _seed_ipeds(conn):
"""Insert minimal IPEDS data for 2 years."""
for year, inst_support, total in [(2020, 100_000, 1_000_000), (2021, 120_000, 1_100_000)]:
conn.execute(
"INSERT INTO raw_ipeds_finance (unitid, year, institutional_support_expenses, total_expenses) VALUES (?, ?, ?, ?)",
[UD_UNITID, year, inst_support, total],
)
for year, enrollment in [(2020, 20000), (2021, 21000)]:
conn.execute(
"INSERT INTO raw_ipeds_enrollment (unitid, year, total_enrollment) VALUES (?, ?, ?)",
[UD_UNITID, year, enrollment],
)
for year, total, faculty, mgmt in [(2020, 3000, 1500, 500), (2021, 3100, 1550, 520)]:
conn.execute(
"INSERT INTO raw_ipeds_staff (unitid, year, total_staff, faculty_total, management_total) VALUES (?, ?, ?, ?, ?)",
[UD_UNITID, year, total, faculty, mgmt],
)
def _seed_cpi(conn):
"""Insert CPI data for 2020-2021."""
for year, value in [(2020, 258.8), (2021, 270.9)]:
for month in range(1, 13):
conn.execute(
"INSERT INTO raw_cpi_u (year, month, value, series_id) VALUES (?, ?, ?, ?)",
[year, month, value, "CUUR0000SA0"],
)
def _seed_990(conn):
"""Insert minimal 990 filing and Schedule J data."""
conn.execute(
"INSERT INTO raw_990_filing (object_id, ein, tax_year, organization_name, total_revenue, total_expenses) "
"VALUES ('obj1', '516000297', 2021, 'UD Foundation', 50000000, 40000000)"
)
conn.execute(
"INSERT INTO raw_990_schedule_j (object_id, ein, tax_year, person_name, title, "
"base_compensation, bonus_compensation, other_compensation, deferred_compensation, "
"nontaxable_benefits, total_compensation) "
"VALUES ('obj1', '516000297', 2021, 'JOHN DOE', 'PRESIDENT', "
"500000, 100000, 10000, 20000, 15000, 645000)"
)
conn.execute(
"INSERT INTO raw_990_schedule_j (object_id, ein, tax_year, person_name, title, "
"base_compensation, bonus_compensation, other_compensation, deferred_compensation, "
"nontaxable_benefits, total_compensation) "
"VALUES ('obj1', '516000297', 2021, 'JANE SMITH', 'PROVOST', "
"400000, 50000, 5000, 15000, 10000, 480000)"
)
class TestEmptyDatabase:
def test_admin_cost_ratio_empty(self, db_conn):
df = query_admin_cost_ratio(db_conn)
assert df.height == 0
def test_top_earners_empty(self, db_conn):
df = query_top_earners(db_conn)
assert df.height == 0
def test_headcount_empty(self, db_conn):
df = query_admin_headcount(db_conn)
assert df.height == 0
class TestAdminCostRatio:
def test_returns_correct_ratio(self, db_conn):
_seed_ipeds(db_conn)
_seed_cpi(db_conn)
df = query_admin_cost_ratio(db_conn)
assert df.height == 2
# 2020: 100000 / 1000000 = 10%
row_2020 = df.filter(df["year"] == 2020)
assert row_2020["admin_cost_pct"][0] == 10.0
class TestAdminPerStudent:
def test_returns_per_student(self, db_conn):
_seed_ipeds(db_conn)
_seed_cpi(db_conn)
df = query_admin_per_student(db_conn)
assert df.height == 2
# 2020: 100000 / 20000 = 5
row_2020 = df.filter(df["year"] == 2020)
assert row_2020["admin_per_student"][0] == 5.0
class TestAdminFacultyRatio:
def test_returns_ratio(self, db_conn):
_seed_ipeds(db_conn)
df = query_admin_faculty_ratio(db_conn)
assert df.height == 2
# 2020: 500 / 1500 = 0.333
row_2020 = df.filter(df["year"] == 2020)
assert row_2020["admin_faculty_ratio"][0] == 0.333
class TestTopEarners:
def test_returns_all(self, db_conn):
_seed_990(db_conn)
df = query_top_earners(db_conn)
assert df.height == 2
assert "canonical_role" in df.columns
def test_filter_by_year(self, db_conn):
_seed_990(db_conn)
df = query_top_earners(db_conn, year=2021)
assert df.height == 2
df_empty = query_top_earners(db_conn, year=2019)
assert df_empty.height == 0
class TestCompByRole:
def test_groups_by_role(self, db_conn):
_seed_990(db_conn)
df = query_comp_by_role(db_conn)
roles = df["canonical_role"].to_list()
assert "PRESIDENT" in roles
assert "PROVOST" in roles
class TestCompVsCpi:
def test_returns_indexed(self, db_conn):
_seed_990(db_conn)
_seed_cpi(db_conn)
df = query_comp_vs_cpi(db_conn)
assert df.height > 0
assert "comp_index" in df.columns
assert "cpi_index" in df.columns
class TestStaffComposition:
def test_computes_other(self, db_conn):
_seed_ipeds(db_conn)
df = query_staff_composition(db_conn)
assert df.height == 2
# 2020: 3000 - 1500 - 500 = 1000
row = df.filter(df["year"] == 2020)
assert row["other_staff"][0] == 1000
class TestGrowthIndex:
def test_base_year_100(self, db_conn):
_seed_ipeds(db_conn)
df = query_growth_index(db_conn)
assert df.height == 2
first = df.filter(df["year"] == 2020)
assert first["mgmt_index"][0] == 100.0
assert first["enrollment_index"][0] == 100.0