Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 43 additions & 3 deletions lms/djangoapps/grades/tests/integration/test_problems.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import ddt
import pytz
from crum import set_current_request
from django.test.utils import override_settings
from xmodule.capa_block import reset_class
from xmodule.graders import ProblemScore
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.tests.django_utils import (
Expand All @@ -25,23 +27,26 @@


@ddt.ddt
class TestMultipleProblemTypesSubsectionScores(SharedModuleStoreTestCase):
class _TestMultipleProblemTypesSubsectionScoresBase(SharedModuleStoreTestCase):
"""
Test grading of different problem types.
"""
__test__ = False
MODULESTORE = TEST_DATA_SPLIT_MODULESTORE

SCORED_BLOCK_COUNT = 7
ACTUAL_TOTAL_POSSIBLE = 17.0

@classmethod
def setUpClass(cls):
reset_class()
super().setUpClass()
cls.load_scoreable_course()
chapter1 = cls.course.get_children()[0]
cls.seq1 = chapter1.get_children()[0]

def setUp(self):
reset_class()
super().setUp()
self.student = UserFactory.create(is_staff=False, username='test_student', password=self.TEST_PASSWORD)
self.client.login(username=self.student.username, password=self.TEST_PASSWORD)
Expand Down Expand Up @@ -98,12 +103,23 @@ def test_score_submission_for_all_problems(self):
assert score.all_total.possible == (possible_per_block * block_count)


@override_settings(USE_EXTRACTED_PROBLEM_BLOCK=True)
class ExtractedTestMultipleProblemTypesSubsectionScores(_TestMultipleProblemTypesSubsectionScoresBase):
__test__ = True


@override_settings(USE_EXTRACTED_PROBLEM_BLOCK=False)
class BuiltInTestMultipleProblemTypesSubsectionScores(_TestMultipleProblemTypesSubsectionScoresBase):
__test__ = True


@ddt.ddt
class TestVariedMetadata(ProblemSubmissionTestMixin, ModuleStoreTestCase):
class _TestVariedMetadataBase(ProblemSubmissionTestMixin, ModuleStoreTestCase):
"""
Test that changing the metadata on a block has the desired effect on the
persisted score.
"""
__test__ = False
MODULESTORE = TEST_DATA_SPLIT_MODULESTORE

default_problem_metadata = {
Expand All @@ -113,6 +129,7 @@ class TestVariedMetadata(ProblemSubmissionTestMixin, ModuleStoreTestCase):
}

def setUp(self):
reset_class()
super().setUp()
self.course = CourseFactory.create()
with self.store.bulk_operations(self.course.id):
Expand Down Expand Up @@ -209,15 +226,27 @@ def test_graded_metadata_alterations(self, alterations, expected_earned, expecte
assert score.graded_total.possible == expected_possible


@override_settings(USE_EXTRACTED_PROBLEM_BLOCK=True)
class ExtractedTestVariedMetadata(_TestVariedMetadataBase):
__test__ = True


@override_settings(USE_EXTRACTED_PROBLEM_BLOCK=False)
class BuiltInTestVariedMetadata(_TestVariedMetadataBase):
__test__ = True


@ddt.ddt
class TestWeightedProblems(SharedModuleStoreTestCase):
class _TestWeightedProblemsBase(SharedModuleStoreTestCase):
"""
Test scores and grades with various problem weight values.
"""
__test__ = False
MODULESTORE = TEST_DATA_SPLIT_MODULESTORE

@classmethod
def setUpClass(cls):
reset_class()
super().setUpClass()
cls.course = CourseFactory.create()
with cls.store.bulk_operations(cls.course.id):
Expand All @@ -237,6 +266,7 @@ def setUpClass(cls):
)

def setUp(self):
reset_class()
super().setUp()
self.user = UserFactory()
self.addCleanup(set_current_request, None)
Expand Down Expand Up @@ -315,3 +345,13 @@ def test_problem_weight(self, raw_earned, raw_possible, weight):
first_attempted=datetime.datetime(2010, 1, 1),
)
self._verify_grades(raw_earned, raw_possible, weight, expected_score)


@override_settings(USE_EXTRACTED_PROBLEM_BLOCK=True)
class ExtractedTestWeightedProblems(_TestWeightedProblemsBase):
__test__ = True


@override_settings(USE_EXTRACTED_PROBLEM_BLOCK=False)
class BuiltInTestWeightedProblems(_TestWeightedProblemsBase):
__test__ = True
14 changes: 13 additions & 1 deletion xmodule/capa_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -2465,5 +2465,17 @@ def randomization_bin(seed, problem_id):
return int(r_hash.hexdigest()[:7], 16) % NUM_RANDOMIZATION_BINS


ProblemBlock = _ExtractedProblemBlock if settings.USE_EXTRACTED_PROBLEM_BLOCK else _BuiltInProblemBlock
ProblemBlock = None


def reset_class():
"""Reset class as per django settings flag"""
global ProblemBlock
ProblemBlock = (
_ExtractedProblemBlock if settings.USE_EXTRACTED_PROBLEM_BLOCK else _BuiltInProblemBlock
)
return ProblemBlock


reset_class()
ProblemBlock.__name__ = "ProblemBlock"
36 changes: 18 additions & 18 deletions xmodule/tests/test_capa_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
)
from xblocks_contrib.problem.capa.tests.test_util import UseUnsafeCodejail
from xblocks_contrib.problem.capa.xqueue_interface import XQueueInterface
from xmodule.capa_block import ComplexEncoder, ProblemBlock
from xmodule.capa_block import ComplexEncoder, _BuiltInProblemBlock as ProblemBlock
from xmodule.tests import DATA_DIR

from ..capa_block import RANDOMIZATION, SHOWANSWER
Expand Down Expand Up @@ -813,7 +813,7 @@ def test_submit_problem_correct(self):
# what the input is, by patching CorrectMap.is_correct()
# Also simulate rendering the HTML
with patch("xblocks_contrib.problem.capa.correctmap.CorrectMap.is_correct") as mock_is_correct:
with patch("xmodule.capa_block.ProblemBlock.get_problem_html") as mock_html:
with patch("xmodule.capa_block._BuiltInProblemBlock.get_problem_html") as mock_html:
mock_is_correct.return_value = True
mock_html.return_value = "Test HTML"

Expand All @@ -833,7 +833,7 @@ def test_submit_problem_correct(self):
assert block.lcp.context["attempt"] == 2

@patch("xblocks_contrib.problem.capa.correctmap.CorrectMap.is_correct")
@patch("xmodule.capa_block.ProblemBlock.get_problem_html")
@patch("xmodule.capa_block._BuiltInProblemBlock.get_problem_html")
def test_submit_problem_with_grading_method_disable(self, mock_html: Mock, mock_is_correct: Mock):
"""
Test that without a specific grading method, the score behaves as
Expand Down Expand Up @@ -873,7 +873,7 @@ def test_submit_problem_with_grading_method_disable(self, mock_html: Mock, mock_
assert block.score == Score(raw_earned=1, raw_possible=1)

@patch("xblocks_contrib.problem.capa.correctmap.CorrectMap.is_correct")
@patch("xmodule.capa_block.ProblemBlock.get_problem_html")
@patch("xmodule.capa_block._BuiltInProblemBlock.get_problem_html")
def test_submit_problem_with_grading_method_enable(self, mock_html: Mock, mock_is_correct: Mock):
"""
Test that the grading method is enabled when submit a problem.
Expand All @@ -895,7 +895,7 @@ def test_submit_problem_with_grading_method_enable(self, mock_html: Mock, mock_i
mock_get_score.assert_called()

@patch("xblocks_contrib.problem.capa.correctmap.CorrectMap.is_correct")
@patch("xmodule.capa_block.ProblemBlock.get_problem_html")
@patch("xmodule.capa_block._BuiltInProblemBlock.get_problem_html")
def test_submit_problem_grading_method_always_enabled(self, mock_html: Mock, mock_is_correct: Mock):
"""
Test problem submission when grading method is always enabled by default.
Expand Down Expand Up @@ -948,7 +948,7 @@ def test_submit_problem_grading_method_always_enabled(self, mock_html: Mock, moc
assert block.score == Score(raw_earned=1, raw_possible=1)

@patch("xblocks_contrib.problem.capa.correctmap.CorrectMap.is_correct")
@patch("xmodule.capa_block.ProblemBlock.get_problem_html")
@patch("xmodule.capa_block._BuiltInProblemBlock.get_problem_html")
def test_submit_problem_grading_method_always_enabled_highest_score(self, mock_html: Mock, mock_is_correct: Mock):
"""
Test problem submission when grading method is always enabled by default
Expand Down Expand Up @@ -1001,7 +1001,7 @@ def test_submit_problem_grading_method_always_enabled_highest_score(self, mock_h
assert block.score == Score(raw_earned=1, raw_possible=1)

@patch("xblocks_contrib.problem.capa.correctmap.CorrectMap.is_correct")
@patch("xmodule.capa_block.ProblemBlock.get_problem_html")
@patch("xmodule.capa_block._BuiltInProblemBlock.get_problem_html")
def test_submit_problem_correct_last_score(self, mock_html: Mock, mock_is_correct: Mock):
"""
Test the `last_score` grading method.
Expand Down Expand Up @@ -1034,7 +1034,7 @@ def test_submit_problem_correct_last_score(self, mock_html: Mock, mock_is_correc
assert block.score == Score(raw_earned=0, raw_possible=1)

@patch("xblocks_contrib.problem.capa.correctmap.CorrectMap.is_correct")
@patch("xmodule.capa_block.ProblemBlock.get_problem_html")
@patch("xmodule.capa_block._BuiltInProblemBlock.get_problem_html")
def test_submit_problem_correct_highest_score(self, mock_html: Mock, mock_is_correct: Mock):
"""
Test the `highest_score` grading method.
Expand Down Expand Up @@ -1066,7 +1066,7 @@ def test_submit_problem_correct_highest_score(self, mock_html: Mock, mock_is_cor
assert block.score == Score(raw_earned=1, raw_possible=1)

@patch("xblocks_contrib.problem.capa.correctmap.CorrectMap.is_correct")
@patch("xmodule.capa_block.ProblemBlock.get_problem_html")
@patch("xmodule.capa_block._BuiltInProblemBlock.get_problem_html")
def test_submit_problem_correct_first_score(self, mock_html: Mock, mock_is_correct: Mock):
"""
Test the `first_score` grading method.
Expand Down Expand Up @@ -1098,7 +1098,7 @@ def test_submit_problem_correct_first_score(self, mock_html: Mock, mock_is_corre
assert block.score == Score(raw_earned=0, raw_possible=1)

@patch("xblocks_contrib.problem.capa.correctmap.CorrectMap.is_correct")
@patch("xmodule.capa_block.ProblemBlock.get_problem_html")
@patch("xmodule.capa_block._BuiltInProblemBlock.get_problem_html")
def test_submit_problem_correct_average_score(self, mock_html: Mock, mock_is_correct: Mock):
"""
Test the `average_score` grading method.
Expand Down Expand Up @@ -1176,7 +1176,7 @@ def test_submit_problem_closed(self):

# Problem closed -- cannot submit
# Simulate that ProblemBlock.closed() always returns True
with patch("xmodule.capa_block.ProblemBlock.closed") as mock_closed:
with patch("xmodule.capa_block._BuiltInProblemBlock.closed") as mock_closed:
mock_closed.return_value = True
with pytest.raises(NotFoundError):
get_request_dict = {CapaFactory.input_key(): "3.14"}
Expand Down Expand Up @@ -1530,7 +1530,7 @@ def test_reset_problem(self):
block.choose_new_seed = Mock(wraps=block.choose_new_seed)

# Stub out HTML rendering
with patch("xmodule.capa_block.ProblemBlock.get_problem_html") as mock_html:
with patch("xmodule.capa_block._BuiltInProblemBlock.get_problem_html") as mock_html:
mock_html.return_value = "<div>Test HTML</div>"

# Reset the problem
Expand All @@ -1553,7 +1553,7 @@ def test_reset_problem_closed(self):
block = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS)

# Simulate that the problem is closed
with patch("xmodule.capa_block.ProblemBlock.closed") as mock_closed:
with patch("xmodule.capa_block._BuiltInProblemBlock.closed") as mock_closed:
mock_closed.return_value = True

# Try to reset the problem
Expand Down Expand Up @@ -1696,7 +1696,7 @@ def test_rescore_problem_with_grading_method_enable(self):
assert block.lcp.context["attempt"] == 1
mock_get_rescore.assert_called()

@patch("xmodule.capa_block.ProblemBlock.publish_grade")
@patch("xmodule.capa_block._BuiltInProblemBlock.publish_grade")
def test_rescore_problem_grading_method_always_enabled(self, mock_publish_grade: Mock):
"""
Test the rescore method when grading method is always enabled by default.
Expand Down Expand Up @@ -1738,7 +1738,7 @@ def test_rescore_problem_grading_method_always_enabled(self, mock_publish_grade:

mock_publish_grade.assert_called_with(score=Score(raw_earned=0.33, raw_possible=1), only_if_higher=False)

@patch("xmodule.capa_block.ProblemBlock.publish_grade")
@patch("xmodule.capa_block._BuiltInProblemBlock.publish_grade")
def test_rescore_problem_grading_method_always_enabled_with_various_methods(self, mock_publish_grade: Mock):
"""
Test the rescore method when grading method is always enabled by default
Expand Down Expand Up @@ -1780,7 +1780,7 @@ def test_rescore_problem_grading_method_always_enabled_with_various_methods(self
block.rescore(only_if_higher=False)
assert block.score == Score(raw_earned=1, raw_possible=1)

@patch("xmodule.capa_block.ProblemBlock.publish_grade")
@patch("xmodule.capa_block._BuiltInProblemBlock.publish_grade")
def test_rescore_problem_update_grading_method(self, mock_publish_grade: Mock):
"""
Test the rescore method when the grading method is updated.
Expand Down Expand Up @@ -1944,7 +1944,7 @@ def test_get_score_with_grading_method(self):
self.assertEqual(score, expected_score)
self.assertEqual(block.score, expected_score)

@patch("xmodule.capa_block.ProblemBlock.score_from_lcp")
@patch("xmodule.capa_block._BuiltInProblemBlock.score_from_lcp")
def test_get_score_with_grading_method_updates_score(self, mock_score_from_lcp: Mock):
"""
Test that the `get_score_with_grading_method` method returns the correct score.
Expand Down Expand Up @@ -2065,7 +2065,7 @@ def test_save_problem_closed(self):
block = CapaFactory.create(done=False)

# Simulate that the problem is closed
with patch("xmodule.capa_block.ProblemBlock.closed") as mock_closed:
with patch("xmodule.capa_block._BuiltInProblemBlock.closed") as mock_closed:
mock_closed.return_value = True

# Try to save the problem
Expand Down
Loading