feat: api function to delete learner's course grades

This commit is contained in:
hajorg
2024-03-22 10:32:54 +01:00
parent 09a8cfcccf
commit 36f3895eaf
5 changed files with 236 additions and 3 deletions

View File

@@ -1,13 +1,17 @@
""" Tests calling the grades api directly """
from unittest.mock import patch
from unittest.mock import patch, Mock
import ddt
from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.grades import api
from lms.djangoapps.grades.models import PersistentSubsectionGrade, PersistentSubsectionGradeOverride
from lms.djangoapps.grades.models import (
PersistentSubsectionGrade,
PersistentSubsectionGradeOverride,
PersistentCourseGrade
)
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.tests.factories import CourseFactory, BlockFactory # lint-amnesty, pylint: disable=wrong-import-order
@@ -56,7 +60,7 @@ class OverrideSubsectionGradeTests(ModuleStoreTestCase):
def tearDown(self):
super().tearDown()
PersistentSubsectionGradeOverride.objects.all().delete() # clear out all previous overrides
PersistentSubsectionGradeOverride.objects.all().delete()
@ddt.data(0.0, None, 3.0)
def test_override_subsection_grade(self, earned_graded):
@@ -108,3 +112,127 @@ class OverrideSubsectionGradeTests(ModuleStoreTestCase):
else:
assert history_entry.history_user is None
assert history_entry.history_user_id is None
class ClearGradeTests(ModuleStoreTestCase):
"""
Tests for the clearing grades api call
"""
@classmethod
def setUpTestData(cls):
super().setUpTestData()
cls.user = UserFactory()
cls.overriding_user = UserFactory()
@classmethod
def tearDownClass(cls):
super().tearDownClass()
def setUp(self):
super().setUp()
self.course = CourseFactory.create(org='edX', number='DemoX', display_name='Demo_Course', run='Spring2019')
self.subsection = BlockFactory.create(parent=self.course, category="sequential", display_name="Subsection")
self.grade = PersistentSubsectionGrade.update_or_create_grade(
user_id=self.user.id,
course_id=self.course.id,
usage_key=self.subsection.location,
first_attempted=None,
visible_blocks=[],
earned_all=6.0,
possible_all=6.0,
earned_graded=5.0,
possible_graded=5.0
)
self.params = {
"user_id": self.user.id,
"course_id": self.course.id,
"course_version": "JoeMcEwing",
"percent_grade": 77.7,
"letter_grade": "Great job",
"passed": True,
}
PersistentCourseGrade.update_or_create(**self.params)
def tearDown(self):
super().tearDown()
PersistentSubsectionGradeOverride.objects.all().delete() # clear out all previous overrides
def test_clear_user_course_grades(self):
api.override_subsection_grade(
self.user.id,
self.course.id,
self.subsection.location,
overrider=self.overriding_user,
earned_graded=0.0,
comment='Test Override Comment',
)
override_obj = api.get_subsection_grade_override(
self.user.id,
self.course.id,
self.subsection.location
)
course_grade = PersistentCourseGrade.read(self.user.id, self.course.id)
self.assertIsNotNone(course_grade)
self.assertIsNotNone(override_obj)
api.clear_user_course_grades(self.user.id, self.course.id)
with self.assertRaises(PersistentCourseGrade.DoesNotExist):
PersistentCourseGrade.read(self.user.id, self.course.id)
with self.assertRaises(PersistentSubsectionGrade.DoesNotExist):
api.get_subsection_grade_override(
self.user.id,
self.course.id,
self.subsection.location
)
def test_clear_wrong_user_course_grades(self):
wrong_user = UserFactory()
api.override_subsection_grade(
self.user.id,
self.course.id,
self.subsection.location,
overrider=self.overriding_user,
earned_graded=0.0,
comment='Test Override Comment',
)
override_obj = api.get_subsection_grade_override(
self.user.id,
self.course.id,
self.subsection.location
)
course_grade = PersistentCourseGrade.read(self.user.id, self.course.id)
self.assertIsNotNone(course_grade)
self.assertIsNotNone(override_obj)
api.clear_user_course_grades(wrong_user.id, self.course.id)
after_clear_override_obj = api.get_subsection_grade_override(
self.user.id,
self.course.id,
self.subsection.location
)
after_clear_course_grade = PersistentCourseGrade.read(self.user.id, self.course.id)
self.assertIsNotNone(after_clear_override_obj)
self.assertIsNotNone(after_clear_course_grade)
@patch('lms.djangoapps.grades.models_api._PersistentSubsectionGrade')
@patch('lms.djangoapps.grades.models_api._PersistentCourseGrade')
@patch('lms.djangoapps.grades.models_api._PersistentSubsectionGradeOverride')
def test_assert_clear_grade_methods_called(self, mock_override, mock_course_grade, mock_subsection_grade):
api.clear_user_course_grades(self.user.id, self.course.id)
mock_override.clear_override.assert_called_with(self.user.id, self.course.id)
mock_course_grade.clear_grade.assert_called_with(self.course.id, self.user.id)
mock_subsection_grade.clear_grade.assert_called_with(self.user.id, self.course.id)
@patch('lms.djangoapps.grades.models_api._PersistentSubsectionGrade')
@patch('lms.djangoapps.grades.models_api._PersistentCourseGrade')
def test_assert_clear_grade_exception(self, mock_course_grade, mock_subsection_grade):
with patch(
'lms.djangoapps.grades.models_api._PersistentSubsectionGradeOverride',
Mock(side_effect=Exception)
) as mock_override:
api.clear_user_course_grades(self.user.id, self.course.id)
self.assertRaises(Exception, mock_override)
self.assertFalse(mock_course_grade.called)
self.assertFalse(mock_subsection_grade.called)