elemes/services/tests/test_composite_score.py

155 lines
3.7 KiB
Python
Raw Normal View History

"""Unit test untuk composite score (pure, tanpa DB).
Ditandai `unit` supaya fixture autouse _isolate_database melewatinya —
tidak butuh PostgreSQL hidup.
"""
import pytest
from services.evaluation import compute_composite
pytestmark = pytest.mark.unit
EX_W = 70.0
QZ_W = 30.0
DONE = 75.0
def test_exercise_quiz_3of4_both_pass():
r = compute_composite(
exercise_passed=True,
quiz_earned=3,
quiz_total=4,
has_exercise=True,
has_quiz=True,
exercise_weight=EX_W,
quiz_weight=QZ_W,
done_min_percent=DONE,
)
assert r.composite_percent == pytest.approx(92.5)
assert r.is_done is True
def test_exercise_passed_quiz_not_attempted():
# Exercise contributes its full weight (70); quiz term contributes 0
# (not attempted) → composite = 70.0, which is < 75 threshold → not done.
r = compute_composite(
exercise_passed=True,
quiz_earned=None,
quiz_total=None,
has_exercise=True,
has_quiz=True,
exercise_weight=EX_W,
quiz_weight=QZ_W,
done_min_percent=DONE,
)
assert r.composite_percent == 70.0
assert r.is_done is False
def test_quiz_attempted_exercise_not_passed():
# Exercise term contributes 0 (not passed); quiz contributes its full
# weight (30) → composite = 30.0, < 75 threshold → not done.
r = compute_composite(
exercise_passed=False,
quiz_earned=4,
quiz_total=4,
has_exercise=True,
has_quiz=True,
exercise_weight=EX_W,
quiz_weight=QZ_W,
done_min_percent=DONE,
)
assert r.composite_percent == 30.0
assert r.is_done is False
def test_exercise_only_passed():
r = compute_composite(
exercise_passed=True,
quiz_earned=None,
quiz_total=None,
has_exercise=True,
has_quiz=False,
exercise_weight=EX_W,
quiz_weight=QZ_W,
done_min_percent=DONE,
)
assert r.composite_percent == 100.0
assert r.is_done is True
def test_exercise_only_not_passed():
r = compute_composite(
exercise_passed=False,
quiz_earned=None,
quiz_total=None,
has_exercise=True,
has_quiz=False,
exercise_weight=EX_W,
quiz_weight=QZ_W,
done_min_percent=DONE,
)
assert r.composite_percent == 0.0
assert r.is_done is False
def test_quiz_only_3of4():
r = compute_composite(
exercise_passed=None,
quiz_earned=3,
quiz_total=4,
has_exercise=False,
has_quiz=True,
exercise_weight=EX_W,
quiz_weight=QZ_W,
done_min_percent=DONE,
)
assert r.composite_percent == 75.0
assert r.is_done is True
def test_quiz_only_1of4():
r = compute_composite(
exercise_passed=None,
quiz_earned=1,
quiz_total=4,
has_exercise=False,
has_quiz=True,
exercise_weight=EX_W,
quiz_weight=QZ_W,
done_min_percent=DONE,
)
assert r.composite_percent == 25.0
assert r.is_done is False
def test_reading_only():
r = compute_composite(
exercise_passed=None,
quiz_earned=None,
quiz_total=None,
has_exercise=False,
has_quiz=False,
exercise_weight=EX_W,
quiz_weight=QZ_W,
done_min_percent=DONE,
)
assert r.composite_percent == 100.0
assert r.is_done is True
def test_exercise_pass_quiz_0of4_below_threshold():
r = compute_composite(
exercise_passed=True,
quiz_earned=0,
quiz_total=4,
has_exercise=True,
has_quiz=True,
exercise_weight=EX_W,
quiz_weight=QZ_W,
done_min_percent=DONE,
)
assert r.composite_percent == 70.0
assert r.is_done is False