.
This commit is contained in:
@@ -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"])
|
||||
Reference in New Issue
Block a user