Files
school_compare/backend/tests/test_whole_school_pupils.py
TudorandClaude Opus 5.5 5f9caad7f4 fix: count pupils as the whole school, not the GCSE year group
fact_performance's total_pupils is the cohort a year's results were
measured on. For a secondary that is Year 11 alone, and the list API sent
it as the card's "pupils": Burntwood showed 245 in search and 1,462 on its
page. The list and place payloads now carry the register's whole-school
count, and nothing when the register has none. Map popups and the compare
basket read the same field.

The header and the wellbeing section fell back to the same results figure
when the census had no record. They now fall back to the register count.
The shell took yearlyData only for that fallback, so the prop is gone and
the results array no longer ships to the client for the chrome.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 22:51:31 +01:00

68 lines
2.6 KiB
Python

"""Cards, map popups and place rows label total_pupils "pupils".
fact_performance's total_pupils is the cohort a year's results were measured
on. For a secondary that is the GCSE year group alone: Burntwood showed 245 in
search against 1,462 on roll. The list and place payloads therefore carry the
register's whole-school count, and nothing when the register has none.
"""
import numpy as np
import pandas as pd
import pytest
from fastapi.testclient import TestClient
def _schools_df() -> pd.DataFrame:
base = {
"local_authority": "Essex", "school_type": "Academy converter",
"year": 202425, "ofsted_grade": 2.0, "ofsted_date": None,
"town": "Brentwood", "postcode": "CM13 1AA", "status": "Open",
"address": "1 Test Street", "latitude": 51.6, "longitude": 0.3,
"gender": "Mixed", "rwm_expected_pct": np.nan, "attainment_8_score": 50.0,
}
rows = [
# Secondary: results cohort 245, register 1,462.
{**base, "urn": 100001, "school_name": "Alpha High", "phase": "Secondary",
"total_pupils": 245, "gias_total_pupils": 1462},
# Register count missing: no count, never the cohort.
{**base, "urn": 100002, "school_name": "Beta High", "phase": "Secondary",
"total_pupils": 180, "gias_total_pupils": np.nan},
]
# Enough schools in one town for it to have a place page.
rows += [
{**base, "urn": 100010 + i, "school_name": f"Gamma High {i}", "phase": "Secondary",
"total_pupils": 200, "gias_total_pupils": 1000 + i}
for i in range(5)
]
return pd.DataFrame(rows)
@pytest.fixture()
def client(monkeypatch):
from backend import app as app_module
monkeypatch.setattr(app_module, "load_latest_school_data", _schools_df)
monkeypatch.setattr(app_module, "load_school_data", _schools_df)
monkeypatch.setattr(app_module, "_place_registry", None)
return TestClient(app_module.app, raise_server_exceptions=False)
def _pupils(schools: list[dict]) -> dict[int, object]:
return {s["urn"]: s.get("total_pupils") for s in schools}
def test_the_list_carries_the_whole_school_count(client):
resp = client.get("/api/schools?page_size=50")
assert resp.status_code == 200, resp.text
pupils = _pupils(resp.json()["schools"])
assert pupils[100001] == 1462
assert pupils[100002] is None
def test_a_place_page_carries_the_whole_school_count(client):
resp = client.get("/api/places/town/brentwood")
assert resp.status_code == 200, resp.text
pupils = _pupils(resp.json()["schools"])
assert pupils[100001] == 1462
assert pupils[100002] is None