This commit is contained in:
Ross
2026-07-13 10:03:33 +01:00
parent 89bf6eedc0
commit 3a3ec75b1d
18 changed files with 514 additions and 24 deletions
+139
View File
@@ -0,0 +1,139 @@
from django.test import TestCase, Client
from django.urls import reverse
from django.contrib.auth.models import User
from generic.models import CidUserExam, CidUser
from physics.models import Exam, Question, UserAnswer
from atlas.models import Case
from atlas.forms import CaseForm
class ScoresStatsTests(TestCase):
def setUp(self):
self.admin = User.objects.create_superuser(
username="admin",
email="admin@example.com",
password="adminpassword"
)
self.client = Client()
self.client.force_login(self.admin)
def test_physics_stats_with_pass_mark_and_exclusion(self):
# Create Exam
exam = Exam.objects.create(name="Physics Test Exam", exam_mode=True)
exam.author.add(self.admin)
# Create Questions (max score will be 10 points)
q1 = Question.objects.create(
stem="stem1",
a="a", a_answer=True,
b="b", b_answer=False,
c="c", c_answer=True,
d="d", d_answer=False,
e="e", e_answer=True,
)
q1.exams.add(exam)
q2 = Question.objects.create(
stem="stem2",
a="a", a_answer=True,
b="b", b_answer=False,
c="c", c_answer=True,
d="d", d_answer=False,
e="e", e_answer=True,
)
q2.exams.add(exam)
# Create two candidates: cid=1 (score=5/10), cid=2 (score=3/10)
UserAnswer.objects.create(
question=q1, exam=exam, cid=1,
a=True, b=False, c=True, d=False, e=True
)
UserAnswer.objects.create(
question=q2, exam=exam, cid=1,
a=False, b=True, c=False, d=True, e=False
)
UserAnswer.objects.create(
question=q1, exam=exam, cid=2,
a=True, b=True, c=True, d=True, e=False
)
# 1. Test stats calculations without custom pass mark (defaults to 50% = 5)
url = reverse("physics:exam_scores_all", kwargs={"pk": exam.pk})
response = self.client.get(f"{url}?stats_only=true")
self.assertEqual(response.status_code, 200)
context = response.context
self.assertEqual(context["pass_mark_threshold"], 5.0)
self.assertEqual(context["passed_candidates_count"], 1)
self.assertEqual(context["pass_rate"], 50.0)
# 2. Update pass mark to 3.0 via HTMX update_pass_mark url
update_url = reverse("physics:update_pass_mark", kwargs={"pk": exam.pk})
update_response = self.client.post(update_url, {"pass_mark": "3.0"}, HTTP_HX_REQUEST="true")
self.assertEqual(update_response.status_code, 302)
exam.refresh_from_db()
self.assertEqual(exam.pass_mark, 3.0)
# Fetch stats again and verify updated pass mark threshold and pass rate
response = self.client.get(f"{url}?stats_only=true")
context = response.context
self.assertEqual(context["pass_mark_threshold"], 3.0)
self.assertEqual(context["passed_candidates_count"], 2)
self.assertEqual(context["pass_rate"], 100.0)
# 3. Exclude cid=2 from stats
exclude_url = reverse("physics:toggle_candidate_stats_exclusion", kwargs={"pk": exam.pk})
exclude_response = self.client.post(f"{exclude_url}?candidate=c/2")
self.assertEqual(exclude_response.status_code, 200)
# Check database status
cid_user = CidUser.objects.get(cid=2)
cux = CidUserExam.objects.get(object_id=exam.pk, cid_user=cid_user)
self.assertTrue(cux.exclude_from_stats)
# Fetch stats again and verify cid=2 is excluded
response = self.client.get(f"{url}?stats_only=true")
context = response.context
self.assertEqual(len(context["cids"]), 1)
self.assertIn("c/1", context["cids"])
self.assertNotIn("c/2", context["cids"])
self.assertEqual(context["mean"], 5.0)
self.assertEqual(context["passed_candidates_count"], 1)
self.assertEqual(context["pass_rate"], 100.0)
def test_case_form_save_commit_false_does_not_persist(self):
form_data = {
"title": "Unsaved Case Form Test",
"description": "Unsaved description",
"diagnostic_certainty": 3,
"open_access": True,
}
form = CaseForm(data=form_data, user=self.admin)
self.assertTrue(form.is_valid())
case_inst = form.save(commit=False)
self.assertIsNone(case_inst.pk)
self.assertEqual(Case.objects.filter(title="Unsaved Case Form Test").count(), 0)
def test_case_linked_series_info(self):
# Create a chain of 3 cases: c1 -> c2 -> c3
c1 = Case.objects.create(title="Case 1")
c2 = Case.objects.create(title="Case 2", previous_case=c1)
c3 = Case.objects.create(title="Case 3", previous_case=c2)
# Verify positions and totals
info1 = c1.get_series_info()
self.assertTrue(info1["in_series"])
self.assertEqual(info1["position"], 1)
self.assertEqual(info1["total"], 3)
info2 = c2.get_series_info()
self.assertTrue(info2["in_series"])
self.assertEqual(info2["position"], 2)
self.assertEqual(info2["total"], 3)
info3 = c3.get_series_info()
self.assertTrue(info3["in_series"])
self.assertEqual(info3["position"], 3)
self.assertEqual(info3["total"], 3)
c4 = Case.objects.create(title="Case 4")
info4 = c4.get_series_info()
self.assertFalse(info4["in_series"])