Commit 4c06585a by Sanford Student

view should always show a weighted grade

parent 6a821d66
...@@ -477,11 +477,10 @@ class DragAndDropBlock( ...@@ -477,11 +477,10 @@ class DragAndDropBlock(
misplaced_items.append(self._get_item_definition(int(item_id))) misplaced_items.append(self._get_item_definition(int(item_id)))
feedback_msgs = [FeedbackMessage(item['feedback']['incorrect'], None) for item in misplaced_items] feedback_msgs = [FeedbackMessage(item['feedback']['incorrect'], None) for item in misplaced_items]
return { return {
'correct': correct, 'correct': correct,
'attempts': self.attempts, 'attempts': self.attempts,
'grade': self._get_raw_earned_if_set(), 'grade': self._get_weighted_earned_if_set(),
'misplaced_items': list(misplaced_ids), 'misplaced_items': list(misplaced_ids),
'feedback': self._present_feedback(feedback_msgs), 'feedback': self._present_feedback(feedback_msgs),
'overall_feedback': self._present_feedback(overall_feedback_msgs) 'overall_feedback': self._present_feedback(overall_feedback_msgs)
...@@ -679,10 +678,9 @@ class DragAndDropBlock( ...@@ -679,10 +678,9 @@ class DragAndDropBlock(
item_feedback_key = 'correct' if is_correct else 'incorrect' item_feedback_key = 'correct' if is_correct else 'incorrect'
item_feedback = FeedbackMessage(item['feedback'][item_feedback_key], None) item_feedback = FeedbackMessage(item['feedback'][item_feedback_key], None)
overall_feedback, __ = self._get_feedback() overall_feedback, __ = self._get_feedback()
return { return {
'correct': is_correct, 'correct': is_correct,
'grade': self._get_raw_earned_if_set(), 'grade': self._get_weighted_earned_if_set(),
'finished': self._is_answer_correct(), 'finished': self._is_answer_correct(),
'overall_feedback': self._present_feedback(overall_feedback), 'overall_feedback': self._present_feedback(overall_feedback),
'feedback': self._present_feedback([item_feedback]) 'feedback': self._present_feedback([item_feedback])
...@@ -809,12 +807,11 @@ class DragAndDropBlock( ...@@ -809,12 +807,11 @@ class DragAndDropBlock(
is_finished = self._is_answer_correct() is_finished = self._is_answer_correct()
else: else:
is_finished = not self.attempts_remain is_finished = not self.attempts_remain
return { return {
'items': item_state, 'items': item_state,
'finished': is_finished, 'finished': is_finished,
'attempts': self.attempts, 'attempts': self.attempts,
'grade': self._get_raw_earned_if_set(), 'grade': self._get_weighted_earned_if_set(),
'overall_feedback': self._present_feedback(overall_feedback_msgs) 'overall_feedback': self._present_feedback(overall_feedback_msgs)
} }
...@@ -946,6 +943,16 @@ class DragAndDropBlock( ...@@ -946,6 +943,16 @@ class DragAndDropBlock(
else: else:
return None return None
def _get_weighted_earned_if_set(self):
"""
Returns student's grade with the problem weight applied if set, otherwise
None.
"""
if self.fields['raw_earned'].is_set_on(self):
return self.weighted_grade()
else:
return None
def _answer_correctness(self): def _answer_correctness(self):
""" """
Checks answer correctness: Checks answer correctness:
......
...@@ -91,14 +91,15 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture): ...@@ -91,14 +91,15 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture):
self.assertEqual(res[self.OVERALL_FEEDBACK_KEY], expected_overall_feedback) self.assertEqual(res[self.OVERALL_FEEDBACK_KEY], expected_overall_feedback)
def test_drop_item_wrong_with_feedback(self): def test_drop_item_wrong_with_feedback(self):
self.block.weight = 2
item_id, zone_id = 0, self.ZONE_2 item_id, zone_id = 0, self.ZONE_2
data = {"val": item_id, "zone": zone_id} data = {"val": item_id, "zone": zone_id}
res = self.call_handler(self.DROP_ITEM_HANDLER, data) res = self.call_handler(self.DROP_ITEM_HANDLER, data)
item_feedback_message = self._make_item_feedback_message(item_id) item_feedback_message = self._make_item_feedback_message(item_id)
expected_feedback = [item_feedback_message] if item_feedback_message else [] expected_feedback = [item_feedback_message] if item_feedback_message else []
# the item was dropped into wrong zone, but we have two items that were correctly left in the bank, # the item was dropped into wrong zone, but we have two items that were correctly left in the bank,
# so the score is 2 / 4.0. # so the raw score is 2 / 4.0.
expected_grade = 2 / 4.0 expected_grade = self.block.weight * 2 / 4.0
self.assertEqual(res, { self.assertEqual(res, {
"overall_feedback": [self._make_feedback_message(message=self.INITIAL_FEEDBACK)], "overall_feedback": [self._make_feedback_message(message=self.INITIAL_FEEDBACK)],
...@@ -109,14 +110,15 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture): ...@@ -109,14 +110,15 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture):
}) })
def test_drop_item_wrong_without_feedback(self): def test_drop_item_wrong_without_feedback(self):
self.block.weight = 2
item_id, zone_id = 2, self.ZONE_1 item_id, zone_id = 2, self.ZONE_1
data = {"val": item_id, "zone": zone_id} data = {"val": item_id, "zone": zone_id}
res = self.call_handler(self.DROP_ITEM_HANDLER, data) res = self.call_handler(self.DROP_ITEM_HANDLER, data)
item_feedback_message = self._make_item_feedback_message(item_id) item_feedback_message = self._make_item_feedback_message(item_id)
expected_feedback = [item_feedback_message] if item_feedback_message else [] expected_feedback = [item_feedback_message] if item_feedback_message else []
# the item was dropped into wrong zone, but we have two items that were correctly left in the bank, # the item was dropped into wrong zone, but we have two items that were correctly left in the bank,
# so the score is 2 / 4.0. # so the raw score is 2 / 4.0.
expected_grade = 2 / 4.0 expected_grade = self.block.weight * 2 / 4.0
self.assertEqual(res, { self.assertEqual(res, {
"overall_feedback": [self._make_feedback_message(message=self.INITIAL_FEEDBACK)], "overall_feedback": [self._make_feedback_message(message=self.INITIAL_FEEDBACK)],
...@@ -127,14 +129,16 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture): ...@@ -127,14 +129,16 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture):
}) })
def test_drop_item_correct(self): def test_drop_item_correct(self):
self.block.weight = 2
item_id, zone_id = 0, self.ZONE_1 item_id, zone_id = 0, self.ZONE_1
data = {"val": item_id, "zone": zone_id} data = {"val": item_id, "zone": zone_id}
res = self.call_handler(self.DROP_ITEM_HANDLER, data) res = self.call_handler(self.DROP_ITEM_HANDLER, data)
item_feedback_message = self._make_item_feedback_message(item_id, key="correct") item_feedback_message = self._make_item_feedback_message(item_id, key="correct")
expected_feedback = [item_feedback_message] if item_feedback_message else [] expected_feedback = [item_feedback_message] if item_feedback_message else []
# Item 0 is in correct zone, items 2 and 3 don't belong to any zone so it is correct to leave them in the bank. # Item 0 is in correct zone, items 2 and 3 don't belong to any zone so it is correct to leave them in the bank.
# The only item that is not in correct position yet is item 1. The grade is therefore 3/4. # The only item that is not in correct position yet is item 1. The grade is therefore 3/4. The weight of the
expected_grade = 3 / 4.0 # problem means that the displayed grade will be 1.5.
expected_grade = self.block.weight * 3 / 4.0
self.assertEqual(res, { self.assertEqual(res, {
"overall_feedback": [self._make_feedback_message(message=self.INITIAL_FEEDBACK)], "overall_feedback": [self._make_feedback_message(message=self.INITIAL_FEEDBACK)],
...@@ -230,12 +234,13 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture): ...@@ -230,12 +234,13 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture):
self.assertEqual({'value': 1, 'max_value': 1, 'only_if_higher': None}, published_grades[-1]) self.assertEqual({'value': 1, 'max_value': 1, 'only_if_higher': None}, published_grades[-1])
def test_drop_item_final(self): def test_drop_item_final(self):
self.block.weight = 2
data = {"val": 0, "zone": self.ZONE_1} data = {"val": 0, "zone": self.ZONE_1}
self.call_handler(self.DROP_ITEM_HANDLER, data) self.call_handler(self.DROP_ITEM_HANDLER, data)
# Item 0 is in correct zone, items 2 and 3 don't belong to any zone so it is correct to leave them in the bank. # Item 0 is in correct zone, items 2 and 3 don't belong to any zone so it is correct to leave them in the bank.
# The only item that is not in correct position yet is item 1. The grade is therefore 3/4. # The only item that is not in correct position yet is item 1. The raw grade is therefore 3/4.
expected_grade = 3 / 4.0 expected_grade = self.block.weight * 3 / 4.0
expected_state = { expected_state = {
"items": { "items": {
"0": {"correct": True, "zone": self.ZONE_1} "0": {"correct": True, "zone": self.ZONE_1}
...@@ -248,8 +253,8 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture): ...@@ -248,8 +253,8 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture):
self.assertEqual(expected_state, self.call_handler('get_user_state', method="GET")) self.assertEqual(expected_state, self.call_handler('get_user_state', method="GET"))
res = self.call_handler(self.DROP_ITEM_HANDLER, {"val": 1, "zone": self.ZONE_2}) res = self.call_handler(self.DROP_ITEM_HANDLER, {"val": 1, "zone": self.ZONE_2})
# All four items are in correct position, so the final grade is 4/4. # All four items are in correct position, so the final raw grade is 4/4.
expected_grade = 4 / 4.0 expected_grade = self.block.weight * 4 / 4.0
self.assertEqual(res, { self.assertEqual(res, {
"overall_feedback": [self._make_feedback_message(message=self.FINAL_FEEDBACK)], "overall_feedback": [self._make_feedback_message(message=self.FINAL_FEEDBACK)],
"finished": True, "finished": True,
...@@ -406,7 +411,7 @@ class AssessmentModeFixture(BaseDragAndDropAjaxFixture): ...@@ -406,7 +411,7 @@ class AssessmentModeFixture(BaseDragAndDropAjaxFixture):
'only_if_higher': None, 'only_if_higher': None,
}) })
self.assertTrue(res['correct']) self.assertTrue(res['correct'])
self.assertEqual(res['grade'], 1) self.assertEqual(res['grade'], self.block.weight)
@ddt.data(*[random.randint(1, 50) for _ in xrange(5)]) # pylint: disable=star-args @ddt.data(*[random.randint(1, 50) for _ in xrange(5)]) # pylint: disable=star-args
def test_do_attempt_incorrect_publish_grade(self, weight): def test_do_attempt_incorrect_publish_grade(self, weight):
...@@ -424,7 +429,7 @@ class AssessmentModeFixture(BaseDragAndDropAjaxFixture): ...@@ -424,7 +429,7 @@ class AssessmentModeFixture(BaseDragAndDropAjaxFixture):
'only_if_higher': None, 'only_if_higher': None,
}) })
self.assertFalse(res['correct']) self.assertFalse(res['correct'])
self.assertEqual(res['grade'], correctness) self.assertEqual(res['grade'], correctness * self.block.weight)
@ddt.data(*[random.randint(1, 50) for _ in xrange(5)]) # pylint: disable=star-args @ddt.data(*[random.randint(1, 50) for _ in xrange(5)]) # pylint: disable=star-args
def test_do_attempt_post_correct_no_publish_grade(self, weight): def test_do_attempt_post_correct_no_publish_grade(self, weight):
...@@ -457,24 +462,25 @@ class AssessmentModeFixture(BaseDragAndDropAjaxFixture): ...@@ -457,24 +462,25 @@ class AssessmentModeFixture(BaseDragAndDropAjaxFixture):
self._set_final_attempt() self._set_final_attempt()
expected_grade = self._submit_partial_solution() expected_raw_grade = self._submit_partial_solution()
expected_weighted_grade = expected_raw_grade * self.block.weight
with mock.patch('workbench.runtime.WorkbenchRuntime.publish', mock.Mock()) as patched_publish: with mock.patch('workbench.runtime.WorkbenchRuntime.publish', mock.Mock()) as patched_publish:
res = self.call_handler(self.DO_ATTEMPT_HANDLER, data={}) res = self.call_handler(self.DO_ATTEMPT_HANDLER, data={})
self.assertTrue(self.block.completed) self.assertTrue(self.block.completed)
patched_publish.assert_called_once_with(self.block, 'grade', { patched_publish.assert_called_once_with(self.block, 'grade', {
'value': expected_grade, 'value': expected_raw_grade,
'max_value': 1, 'max_value': 1,
'only_if_higher': None, 'only_if_higher': None,
}) })
expected_grade_feedback = self._make_feedback_message( expected_grade_feedback = self._make_feedback_message(
FeedbackMessages.FINAL_ATTEMPT_TPL.format(score=expected_grade * self.block.weight), FeedbackMessages.FINAL_ATTEMPT_TPL.format(score=expected_weighted_grade),
FeedbackMessages.MessageClasses.PARTIAL_SOLUTION FeedbackMessages.MessageClasses.PARTIAL_SOLUTION
) )
self.assertIn(expected_grade_feedback, res[self.OVERALL_FEEDBACK_KEY]) self.assertIn(expected_grade_feedback, res[self.OVERALL_FEEDBACK_KEY])
self.assertEqual(res['grade'], expected_grade) self.assertEqual(res['grade'], expected_weighted_grade)
@ddt.data(*[random.randint(1, 50) for _ in xrange(5)]) # pylint: disable=star-args @ddt.data(*[random.randint(1, 50) for _ in xrange(5)]) # pylint: disable=star-args
def test_do_attempt_incorrect_final_attempt_after_correct(self, weight): def test_do_attempt_incorrect_final_attempt_after_correct(self, weight):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment