"""교수자 대시보드 집계 테스트.""" from __future__ import annotations import unittest from unittest.mock import AsyncMock, patch from .deps import Principal, Role from .routes import teacher from .services import state_machine from .services.persona import P1 from .store import InProcSession, TurnRecord def _principal() -> Principal: return Principal( user_id="00000000-0000-0000-0000-000000000901", role=Role.TEACHER, ) def _session( *, session_id: str, session_no: int, learner_id: str, score: str, rapport: float, technique: str, created_at: float, ) -> InProcSession: state = state_machine.init_state(params=P1.openness_params()) state.stage = state_machine.Stage.EXPLORE return InProcSession( session_id=session_id, case_id=session_id, learner_id=learner_id, persona_code=P1.code, theory_mode="humanistic", persona=P1, state=state, session_no=session_no, created_at=created_at, ended_at=created_at + 600, ended=True, turns=[ TurnRecord( turn_seq=1, speaker="counselor", stage=state.stage.value, text="상담자 발화", text_masked="상담자 발화", evaluation={ "appropriateness": score, "rapport_signal": rapport, "techniques": [{"label": technique}], }, ), TurnRecord( turn_seq=2, speaker="client", stage=state.stage.value, text="내담자 응답", text_masked="내담자 응답", ), ], ) class TeacherDashboardGrowthTest(unittest.IsolatedAsyncioTestCase): async def test_dashboard_returns_learner_growth_from_turn_evaluations(self) -> None: learner_id = "00000000-0000-0000-0000-000000000111" sessions = [ _session( session_id="00000000-0000-0000-0000-00000000a111", session_no=1, learner_id=learner_id, score="neutral", rapport=0.1, technique="reflection", created_at=1_000.0, ), _session( session_id="00000000-0000-0000-0000-00000000a112", session_no=2, learner_id=learner_id, score="pos", rapport=0.5, technique="reflection", created_at=2_000.0, ), ] principal = _principal() with ( patch.object( teacher.session_persistence, "list_sessions", AsyncMock(return_value=(sessions, True)), ) as list_sessions, patch.object( teacher.session_persistence, "list_safety_alerts", AsyncMock(return_value=([], True)), ), ): response = await teacher.teacher_dashboard(principal) list_sessions.assert_awaited_once_with(principal, include_turn_evaluation=True) self.assertEqual(response.total_learners, 1) self.assertEqual(len(response.learner_growth), 1) growth = response.learner_growth[0] self.assertEqual(growth.sessions, 2) self.assertEqual(growth.ended_sessions, 2) self.assertEqual(growth.first_score, 0.5) self.assertEqual(growth.latest_score, 1.0) self.assertEqual(growth.score_delta, 0.5) self.assertEqual(growth.trend, "up") self.assertEqual(growth.top_techniques, ["reflection"]) self.assertEqual([point.session_no for point in growth.points], [1, 2]) if __name__ == "__main__": unittest.main()