def test_peer_assess_for_already_cancelled_submission(self, xblock): # Create a submission for this problem from another user student_item = xblock.get_student_item_dict() submission = xblock.create_submission(student_item, self.SUBMISSION) # Create a submission for the scorer (required before assessing another student) another_student = copy.deepcopy(student_item) another_submission = xblock.create_submission(another_student, self.SUBMISSION) assessment = self.ASSESSMENT assessment["submission_uuid"] = assessment.get("submission_uuid", submission.get("uuid", None)) # Pull the submission to assess peer_api.get_submission_to_assess(another_submission["uuid"], 3) requirements = {"peer": {"must_grade": 1, "must_be_graded_by": 1}} workflow_api.cancel_workflow( submission_uuid=submission["uuid"], comments="Inappropriate language", cancelled_by_id=another_student["student_id"], assessment_requirements=requirements, ) # Submit an assessment and expect a failure resp = self.request(xblock, "peer_assess", json.dumps(assessment), response_format="json") self.assertEqual(resp["success"], False) self.assertGreater(len(resp["msg"]), 0)
def test_staff_debug_student_info_full_workflow(self, xblock): # Simulate that we are course staff xblock.xmodule_runtime = self._create_mock_runtime( xblock.scope_ids.usage_id, True, False, "Bob" ) # Commonly chosen options for assessments options_selected = { "Ideas": "Good", "Content": "Poor", } criterion_feedback = { "Ideas": "Dear diary: Lots of creativity from my dream journal last night at 2 AM,", "Content": "Not as insightful as I had thought in the wee hours of the morning!" } overall_feedback = "I think I should tell more people about how important worms are for the ecosystem." bob_item = STUDENT_ITEM.copy() bob_item["item_id"] = xblock.scope_ids.usage_id # Create a submission for Bob, and corresponding workflow. submission = sub_api.create_submission(bob_item, {'text':"Bob Answer"}) peer_api.on_start(submission["uuid"]) workflow_api.create_workflow(submission["uuid"], ['peer', 'self']) # Create a submission for Tim, and corresponding workflow. tim_item = bob_item.copy() tim_item["student_id"] = "Tim" tim_sub = sub_api.create_submission(tim_item, "Tim Answer") peer_api.on_start(tim_sub["uuid"]) workflow_api.create_workflow(tim_sub["uuid"], ['peer', 'self']) # Bob assesses Tim. peer_api.get_submission_to_assess(submission['uuid'], 1) peer_api.create_assessment( submission["uuid"], STUDENT_ITEM["student_id"], options_selected, dict(), "", {'criteria': xblock.rubric_criteria}, 1, ) # Bob assesses himself. self_api.create_assessment( submission['uuid'], STUDENT_ITEM["student_id"], options_selected, criterion_feedback, overall_feedback, {'criteria': xblock.rubric_criteria}, ) # Now Bob should be fully populated in the student info view. request = namedtuple('Request', 'params') request.params = {"student_id": "Bob"} # Verify that we can render without error resp = xblock.render_student_info(request) self.assertIn("bob answer", resp.body.lower())
def test_get_submitted_assessments_error(self, mock_filter): self._create_student_and_submission("Tim", "Tim's answer") bob_sub, bob = self._create_student_and_submission("Bob", "Bob's answer") peer_api.get_submission_to_assess(bob_sub['uuid'], REQUIRED_GRADED_BY) mock_filter.side_effect = DatabaseError("Oh no.") submitted_assessments = peer_api.get_submitted_assessments(bob_sub["uuid"], scored_only=False) self.assertEqual(1, len(submitted_assessments))
def test_staff_debug_student_info_peer_only(self, xblock): # Simulate that we are course staff xblock.xmodule_runtime = self._create_mock_runtime( xblock.scope_ids.usage_id, True, False, "Bob" ) bob_item = STUDENT_ITEM.copy() bob_item["item_id"] = xblock.scope_ids.usage_id # Create a submission for Bob, and corresponding workflow. submission = sub_api.create_submission(bob_item, {'text':"Bob Answer"}) peer_api.on_start(submission["uuid"]) workflow_api.create_workflow(submission["uuid"], ['peer']) # Create a submission for Tim, and corresponding workflow. tim_item = bob_item.copy() tim_item["student_id"] = "Tim" tim_sub = sub_api.create_submission(tim_item, "Tim Answer") peer_api.on_start(tim_sub["uuid"]) workflow_api.create_workflow(tim_sub["uuid"], ['peer', 'self']) # Bob assesses Tim. peer_api.get_submission_to_assess(submission['uuid'], 1) peer_api.create_assessment( submission["uuid"], STUDENT_ITEM["student_id"], ASSESSMENT_DICT['options_selected'], dict(), "", {'criteria': xblock.rubric_criteria}, 1, ) # Now Bob should be fully populated in the student info view. path, context = xblock.get_student_info_path_and_context("Bob") self.assertEquals("Bob Answer", context['submission']['answer']['text']) self.assertIsNone(context['self_assessment']) self.assertEquals("openassessmentblock/staff_debug/student_info.html", path)
def _peer_assess(scores): """ Helper to fulfill peer assessment requirements. """ bob_sub, bob = TestStaffAssessment._create_student_and_submission("Bob", "Bob's answer", problem_steps=['peer']) peer_api.get_submission_to_assess(bob_sub["uuid"], 1) return peer_assess(bob_sub["uuid"], bob["student_id"], scores, dict(), "", RUBRIC, 1)
def test_create_assessment_with_feedback(self): self._create_student_and_submission("Tim", "Tim's answer") bob_sub, bob = self._create_student_and_submission("Bob", "Bob's answer") peer_api.get_submission_to_assess(bob_sub['uuid'], 1) # Creating feedback per criterion should need one additional query to update # for each criterion that has feedback. with self.assertNumQueries(self.CREATE_ASSESSMENT_NUM_QUERIES + 1): assessment = peer_api.create_assessment( bob_sub["uuid"], bob["student_id"], ASSESSMENT_DICT['options_selected'], ASSESSMENT_DICT['criterion_feedback'], ASSESSMENT_DICT['overall_feedback'], RUBRIC_DICT, REQUIRED_GRADED_BY, ) self.assertEqual(assessment["feedback"], ASSESSMENT_DICT["overall_feedback"]) # The parts are not guaranteed to be in any particular order, # so we need to iterate through and check them by name. # If we haven't explicitly set feedback for the criterion, expect # that it defaults to an empty string. for part in assessment['parts']: criterion_name = part['option']['criterion']['name'] expected_feedback = ASSESSMENT_DICT['criterion_feedback'].get(criterion_name, "") self.assertEqual(part['feedback'], expected_feedback)
def test_staff_area_student_info_full_workflow(self, xblock): # Simulate that we are course staff xblock.xmodule_runtime = self._create_mock_runtime( xblock.scope_ids.usage_id, True, False, "Bob" ) xblock.runtime._services['user'] = NullUserService() # pylint: disable=protected-access # Commonly chosen options for assessments options_selected = { u"𝓒𝓸𝓷𝓬𝓲𝓼𝓮": u"Ġööḋ", u"Form": u"Poor", } criterion_feedback = { u"𝓒𝓸𝓷𝓬𝓲𝓼𝓮": u"Dear diary: Lots of creativity from my dream journal last night at 2 AM,", u"Form": u"Not as insightful as I had thought in the wee hours of the morning!" } overall_feedback = "I think I should tell more people about how important worms are for the ecosystem." bob_item = STUDENT_ITEM.copy() bob_item["item_id"] = xblock.scope_ids.usage_id # Create a submission for Bob, and corresponding workflow. submission = self._create_submission(bob_item, {'text': "Bob Answer"}, ['peer', 'self']) # Create a submission for Tim, and corresponding workflow. tim_item = bob_item.copy() tim_item["student_id"] = "Tim" self._create_submission(tim_item, "Tim Answer", ['peer', 'self']) # Bob assesses Tim. peer_api.get_submission_to_assess(submission['uuid'], 1) peer_api.create_assessment( submission["uuid"], STUDENT_ITEM["student_id"], options_selected, dict(), "", {'criteria': xblock.rubric_criteria}, 1, ) # Bob assesses himself. self_api.create_assessment( submission['uuid'], STUDENT_ITEM["student_id"], options_selected, criterion_feedback, overall_feedback, {'criteria': xblock.rubric_criteria}, ) # Now Bob should be fully populated in the student info view. request = namedtuple('Request', 'params') request.params = {"student_username": "******"} # Verify that we can render without error resp = xblock.render_student_info(request) self.assertIn("bob answer", resp.body.lower())
def _peer_assess(scores): """ Helper to fulfill peer assessment requirements. """ bob_sub, bob = TestStaffAssessment._create_student_and_submission( "Bob", "Bob's answer", problem_steps=['peer']) peer_api.get_submission_to_assess(bob_sub["uuid"], 1) return peer_assess(bob_sub["uuid"], bob["student_id"], scores, dict(), "", RUBRIC, 1)
def _submit_peer_assessment(self, xblock, student_id, scorer_id, assessment, expect_failure=False): """ Create submissions for a student and scorer, then create a peer assessment from the scorer. Args: xblock (OpenAssessmentBlock) student_id (unicode): The ID of the student being assessed. scorer_id (unicode): The ID of the student creating the assessment. assessment (dict): Serialized assessment model. Keyword Arguments: expect_failure (bool): If true, expect a failure response and return None Returns: dict: The peer assessment retrieved from the API. """ # Create a submission for this problem from another user student_item = xblock.get_student_item_dict() student_item['student_id'] = student_id submission = xblock.create_submission(student_item, self.SUBMISSION) # Create a submission for the scorer (required before assessing another student) another_student = copy.deepcopy(student_item) another_student['student_id'] = scorer_id another_submission = xblock.create_submission(another_student, self.SUBMISSION) # Pull the submission to assess peer_api.get_submission_to_assess(another_submission['uuid'], 3) # Submit an assessment and expect a successful response assessment = copy.deepcopy(assessment) assessment['submission_uuid'] = assessment.get( 'submission_uuid', submission.get('uuid', None)) resp = self.request(xblock, 'peer_assess', json.dumps(assessment), response_format='json') if expect_failure: self.assertFalse(resp['success']) return None else: self.assertTrue(resp['success']) # Retrieve the peer assessment retrieved_assessment = peer_api.get_assessments( submission['uuid'])[0] return submission['uuid'], retrieved_assessment
def test_provisionally_done(self): """ Test to ensure that blocking steps, such as peer, are not considered done and do not display a score if the submitter's requirements have not yet been met, even if a staff score has been recorded. This test also ensures that a user may submit peer assessments after having been staff assessed, which was a bug that had been previously present. """ # Tim(student) makes a submission, for a problem that requires peer assessment tim_sub, _ = TestStaffAssessment._create_student_and_submission( "Tim", "Tim's answer", problem_steps=['peer']) # Bob(student) also makes a submission for that problem bob_sub, bob = TestStaffAssessment._create_student_and_submission( "Bob", "Bob's answer", problem_steps=['peer']) # Define peer requirements. Note that neither submission will fulfill must_be_graded_by requirements = {"peer": {"must_grade": 1, "must_be_graded_by": 2}} staff_score = "none" # Dumbledore(staff) uses override ability to provide a score for both submissions staff_api.create_assessment( tim_sub["uuid"], "Dumbledore", OPTIONS_SELECTED_DICT[staff_score]["options"], dict(), "", RUBRIC, ) staff_api.create_assessment( bob_sub["uuid"], "Dumbledore", OPTIONS_SELECTED_DICT[staff_score]["options"], dict(), "", RUBRIC, ) # Bob completes his peer assessment duties, Tim does not peer_api.get_submission_to_assess(bob_sub["uuid"], 1) peer_assess(bob_sub["uuid"], bob["student_id"], OPTIONS_SELECTED_DICT["most"]["options"], dict(), "", RUBRIC, requirements["peer"]["must_be_graded_by"]) # Verify that Bob's submission is marked done and returns the proper score bob_workflow = workflow_api.get_workflow_for_submission( bob_sub["uuid"], requirements) self.assertEqual(bob_workflow["score"]["points_earned"], OPTIONS_SELECTED_DICT[staff_score]["expected_points"]) self.assertEqual(bob_workflow["status"], "done") # Verify that Tim's submission is not marked done, and he cannot get his score tim_workflow = workflow_api.get_workflow_for_submission( tim_sub["uuid"], requirements) self.assertEqual(tim_workflow["score"], None) self.assertNotEqual(tim_workflow["status"], "done")
def test_load_peer_student_view_with_dates(self, xblock): student_item = xblock.get_student_item_dict() sally_student_item = copy.deepcopy(student_item) sally_student_item['student_id'] = "Sally" sally_submission = xblock.create_submission( sally_student_item, (u"Sally's answer 1", u"Sally's answer 2")) # Hal comes and submits a response. hal_student_item = copy.deepcopy(student_item) hal_student_item['student_id'] = "Hal" hal_submission = xblock.create_submission( hal_student_item, (u"Hal's answer 1", u"Hal's answer 2")) # Now Hal will assess Sally. assessment = copy.deepcopy(self.ASSESSMENT) peer_api.get_submission_to_assess(hal_submission['uuid'], 1) peer_api.create_assessment(hal_submission['uuid'], hal_student_item['student_id'], assessment['options_selected'], assessment['criterion_feedback'], assessment['overall_feedback'], {'criteria': xblock.rubric_criteria}, 1) # Now Sally will assess Hal. assessment = copy.deepcopy(self.ASSESSMENT) peer_api.get_submission_to_assess(sally_submission['uuid'], 1) peer_api.create_assessment(sally_submission['uuid'], sally_student_item['student_id'], assessment['options_selected'], assessment['criterion_feedback'], assessment['overall_feedback'], {'criteria': xblock.rubric_criteria}, 1) # If Over Grading is on, this should now return Sally or Hal's response to Bob. submission = xblock.create_submission( student_item, (u"Bob's answer 1", u"Bob's answer 2")) workflow_info = xblock.get_workflow_info() self.assertEqual(workflow_info["status"], u'peer') # Validate Submission Rendering. request = namedtuple('Request', 'params') request.params = {} peer_response = xblock.render_peer_assessment(request) self.assertIsNotNone(peer_response) self.assertNotIn( submission["answer"]["parts"][0]["text"].encode('utf-8'), peer_response.body) self.assertNotIn( submission["answer"]["parts"][1]["text"].encode('utf-8'), peer_response.body) # Validate Peer Rendering. self.assertTrue("Sally".encode('utf-8') in peer_response.body or "Hal".encode('utf-8') in peer_response.body)
def test_load_peer_student_view_with_dates(self, xblock): student_item = xblock.get_student_item_dict() sally_student_item = copy.deepcopy(student_item) sally_student_item['student_id'] = "Sally" sally_submission = xblock.create_submission(sally_student_item, (u"Sally's answer 1", u"Sally's answer 2")) # Hal comes and submits a response. hal_student_item = copy.deepcopy(student_item) hal_student_item['student_id'] = "Hal" hal_submission = xblock.create_submission(hal_student_item, (u"Hal's answer 1", u"Hal's answer 2")) # Now Hal will assess Sally. assessment = copy.deepcopy(self.ASSESSMENT) peer_api.get_submission_to_assess(hal_submission['uuid'], 1) peer_api.create_assessment( hal_submission['uuid'], hal_student_item['student_id'], assessment['options_selected'], assessment['criterion_feedback'], assessment['overall_feedback'], {'criteria': xblock.rubric_criteria}, 1 ) # Now Sally will assess Hal. assessment = copy.deepcopy(self.ASSESSMENT) peer_api.get_submission_to_assess(sally_submission['uuid'], 1) peer_api.create_assessment( sally_submission['uuid'], sally_student_item['student_id'], assessment['options_selected'], assessment['criterion_feedback'], assessment['overall_feedback'], {'criteria': xblock.rubric_criteria}, 1 ) # If Over Grading is on, this should now return Sally or Hal's response to Bob. submission = xblock.create_submission(student_item, (u"Bob's answer 1", u"Bob's answer 2")) workflow_info = xblock.get_workflow_info() self.assertEqual(workflow_info["status"], u'peer') # Validate Submission Rendering. request = namedtuple('Request', 'params') request.params = {} peer_response = xblock.render_peer_assessment(request) self.assertIsNotNone(peer_response) self.assertNotIn(submission["answer"]["parts"][0]["text"].encode('utf-8'), peer_response.body) self.assertNotIn(submission["answer"]["parts"][1]["text"].encode('utf-8'), peer_response.body) # Validate Peer Rendering. self.assertTrue("Sally".encode('utf-8') in peer_response.body or "Hal".encode('utf-8') in peer_response.body)
def test_create_feedback_on_an_assessment(self): tim_sub, tim = self._create_student_and_submission("Tim", "Tim's answer") bob_sub, bob = self._create_student_and_submission("Bob", "Bob's answer") peer_api.get_submission_to_assess(bob_sub['uuid'], 1) assessment = peer_api.create_assessment( bob_sub["uuid"], bob["student_id"], ASSESSMENT_DICT['options_selected'], ASSESSMENT_DICT['criterion_feedback'], ASSESSMENT_DICT['overall_feedback'], RUBRIC_DICT, REQUIRED_GRADED_BY, ) peer_api.get_submission_to_assess(tim_sub['uuid'], 1) peer_api.create_assessment( tim_sub["uuid"], tim["student_id"], ASSESSMENT_DICT['options_selected'], ASSESSMENT_DICT['criterion_feedback'], ASSESSMENT_DICT['overall_feedback'], RUBRIC_DICT, REQUIRED_GRADED_BY, ) peer_api.get_score( tim_sub["uuid"], { 'must_grade': 1, 'must_be_graded_by': 1 } ) feedback = peer_api.get_assessment_feedback(tim_sub['uuid']) self.assertIsNone(feedback) peer_api.set_assessment_feedback( { 'submission_uuid': tim_sub['uuid'], 'feedback_text': 'Bob is a jerk!', 'options': [ 'I disliked this assessment', 'I felt this assessment was unfair', ] } ) saved_feedback = peer_api.get_assessment_feedback(tim_sub['uuid']) self.assertIsNot(saved_feedback, None) self.assertEquals(saved_feedback['submission_uuid'], assessment['submission_uuid']) self.assertEquals(saved_feedback['feedback_text'], 'Bob is a jerk!') self.assertItemsEqual(saved_feedback['options'], [ {'text': 'I disliked this assessment'}, {'text': 'I felt this assessment was unfair'}, ]) self.assertEquals(saved_feedback["assessments"][0]["submission_uuid"], assessment["submission_uuid"])
def test_staff_debug_student_info_full_workflow(self, xblock): # Simulate that we are course staff xblock.xmodule_runtime = self._create_mock_runtime( xblock.scope_ids.usage_id, True, False, "Bob" ) # Commonly chosen options for assessments options_selected = { "Ideas": "Good", "Content": "Poor", } bob_item = STUDENT_ITEM.copy() bob_item["item_id"] = xblock.scope_ids.usage_id # Create a submission for Bob, and corresponding workflow. submission = sub_api.create_submission(bob_item, {'text':"Bob Answer"}) peer_api.on_start(submission["uuid"]) workflow_api.create_workflow(submission["uuid"], ['peer', 'self']) # Create a submission for Tim, and corresponding workflow. tim_item = bob_item.copy() tim_item["student_id"] = "Tim" tim_sub = sub_api.create_submission(tim_item, "Tim Answer") peer_api.on_start(tim_sub["uuid"]) workflow_api.create_workflow(tim_sub["uuid"], ['peer', 'self']) # Bob assesses Tim. peer_api.get_submission_to_assess(submission['uuid'], 1) peer_api.create_assessment( submission["uuid"], STUDENT_ITEM["student_id"], options_selected, dict(), "", {'criteria': xblock.rubric_criteria}, 1, ) # Bob assesses himself. self_api.create_assessment( submission['uuid'], STUDENT_ITEM["student_id"], options_selected, {'criteria': xblock.rubric_criteria}, ) # Now Bob should be fully populated in the student info view. request = namedtuple('Request', 'params') request.params = {"student_id": "Bob"} # Verify that we can render without error resp = xblock.render_student_info(request) self.assertIn("bob answer", resp.body.lower())
def setUp(self): super(TestOraAggregateDataIntegration, self).setUp() # Create submissions and assessments self.submission = self._create_submission(STUDENT_ITEM) self.scorer_submission = self._create_submission(SCORER_ITEM) self.earned_points = 1 self.possible_points = 2 peer_api.get_submission_to_assess(self.scorer_submission['uuid'], 1) self.assessment = self._create_assessment(self.scorer_submission['uuid']) sub_api.set_score(self.submission['uuid'], self.earned_points, self.possible_points) self.score = sub_api.get_score(STUDENT_ITEM) peer_api.get_score(self.submission['uuid'], {'must_be_graded_by': 1, 'must_grade': 0}) self._create_assessment_feedback(self.submission['uuid'])
def test_provisionally_done(self): """ Test to ensure that blocking steps, such as peer, are not considered done and do not display a score if the submitter's requirements have not yet been met, even if a staff score has been recorded. This test also ensures that a user may submit peer assessments after having been staff assessed, which was a bug that had been previously present. """ # Tim(student) makes a submission, for a problem that requires peer assessment tim_sub, _ = TestStaffAssessment._create_student_and_submission("Tim", "Tim's answer", problem_steps=['peer']) # Bob(student) also makes a submission for that problem bob_sub, bob = TestStaffAssessment._create_student_and_submission("Bob", "Bob's answer", problem_steps=['peer']) # Define peer requirements. Note that neither submission will fulfill must_be_graded_by requirements = {"peer": {"must_grade": 1, "must_be_graded_by": 2}} staff_score = "none" # Dumbledore(staff) uses override ability to provide a score for both submissions staff_api.create_assessment( tim_sub["uuid"], "Dumbledore", OPTIONS_SELECTED_DICT[staff_score]["options"], dict(), "", RUBRIC, ) staff_api.create_assessment( bob_sub["uuid"], "Dumbledore", OPTIONS_SELECTED_DICT[staff_score]["options"], dict(), "", RUBRIC, ) # Bob completes his peer assessment duties, Tim does not peer_api.get_submission_to_assess(bob_sub["uuid"], 1) peer_assess( bob_sub["uuid"], bob["student_id"], OPTIONS_SELECTED_DICT["most"]["options"], dict(), "", RUBRIC, requirements["peer"]["must_be_graded_by"] ) # Verify that Bob's submission is marked done and returns the proper score bob_workflow = workflow_api.get_workflow_for_submission(bob_sub["uuid"], requirements) self.assertEqual(bob_workflow["score"]["points_earned"], OPTIONS_SELECTED_DICT[staff_score]["expected_points"]) self.assertEqual(bob_workflow["status"], "done") # Verify that Tim's submission is not marked done, and he cannot get his score tim_workflow = workflow_api.get_workflow_for_submission(tim_sub["uuid"], requirements) self.assertEqual(tim_workflow["score"], None) self.assertNotEqual(tim_workflow["status"], "done")
def test_create_assessment_points(self): self._create_student_and_submission("Tim", "Tim's answer") bob_sub, bob = self._create_student_and_submission("Bob", "Bob's answer") peer_api.get_submission_to_assess(bob_sub['uuid'], 1) with self.assertNumQueries(self.CREATE_ASSESSMENT_NUM_QUERIES): assessment = peer_api.create_assessment( bob_sub["uuid"], bob["student_id"], ASSESSMENT_DICT['options_selected'], dict(), "", RUBRIC_DICT, REQUIRED_GRADED_BY, ) self.assertEqual(assessment["points_earned"], 6) self.assertEqual(assessment["points_possible"], 14)
def setUp(self): super(TestOraAggregateDataIntegration, self).setUp() self.maxDiff = None # pylint: disable=invalid-name # Create submissions and assessments self.submission = self._create_submission(STUDENT_ITEM) self.scorer_submission = self._create_submission(SCORER_ITEM) self.earned_points = 1 self.possible_points = 2 peer_api.get_submission_to_assess(self.scorer_submission['uuid'], 1) self.assessment = self._create_assessment(self.scorer_submission['uuid']) self.assertEqual(self.assessment['parts'][0]['criterion']['label'], "criterion_1") sub_api.set_score(self.submission['uuid'], self.earned_points, self.possible_points) self.score = sub_api.get_score(STUDENT_ITEM) peer_api.get_score(self.submission['uuid'], {'must_be_graded_by': 1, 'must_grade': 0}) self._create_assessment_feedback(self.submission['uuid'])
def get_peer_submission(self, student_item_dict, assessment): """ Retrieve a submission to peer-assess. Args: student_item_dict (dict): The student item for the student creating the submission. assessment (dict): A dict describing the requirements for grading. Returns: dict: The serialized submission model. """ peer_submission = False try: peer_submission = peer_api.get_submission_to_assess( self.submission_uuid, assessment["must_be_graded_by"] ) self.runtime.publish( self, "openassessmentblock.get_peer_submission", { "requesting_student_id": student_item_dict["student_id"], "course_id": student_item_dict["course_id"], "item_id": student_item_dict["item_id"], "submission_returned_uuid": ( peer_submission["uuid"] if peer_submission else None ) } ) except PeerAssessmentWorkflowError as err: logger.exception(err) return peer_submission
def test_close_active_assessment(self): buffy_answer, _ = self._create_student_and_submission("Buffy", "Buffy's answer") xander_answer, _ = self._create_student_and_submission("Xander", "Xander's answer") # Create a workflow for Buffy. buffy_workflow = PeerWorkflow.get_by_submission_uuid(buffy_answer['uuid']) # Get a workflow item opened up. submission = peer_api.get_submission_to_assess(buffy_answer['uuid'], 3) self.assertEqual(xander_answer["uuid"], submission["uuid"]) assessment_dict = peer_api.create_assessment( buffy_answer["uuid"], "Buffy", ASSESSMENT_DICT['options_selected'], ASSESSMENT_DICT['criterion_feedback'], ASSESSMENT_DICT['overall_feedback'], RUBRIC_DICT, REQUIRED_GRADED_BY, ) assessment = Assessment.objects.filter( scorer_id=assessment_dict["scorer_id"], scored_at=assessment_dict["scored_at"])[0] buffy_workflow.close_active_assessment(xander_answer["uuid"], assessment, REQUIRED_GRADED_BY) item = PeerWorkflowItem.objects.get(submission_uuid=xander_answer['uuid']) self.assertEqual(xander_answer["uuid"], submission["uuid"]) self.assertIsNotNone(item.assessment)
def test_staff_debug_student_info_full_workflow(self, xblock): # Simulate that we are course staff xblock.xmodule_runtime = self._create_mock_runtime( xblock.scope_ids.usage_id, True, "Bob") bob_item = STUDENT_ITEM.copy() bob_item["item_id"] = xblock.scope_ids.usage_id # Create a submission for Bob, and corresponding workflow. submission = sub_api.create_submission(bob_item, {'text': "Bob Answer"}) peer_api.create_peer_workflow(submission["uuid"]) workflow_api.create_workflow(submission["uuid"], ['peer', 'self']) # Create a submission for Tim, and corresponding workflow. tim_item = bob_item.copy() tim_item["student_id"] = "Tim" tim_sub = sub_api.create_submission(tim_item, "Tim Answer") peer_api.create_peer_workflow(tim_sub["uuid"]) workflow_api.create_workflow(tim_sub["uuid"], ['peer', 'self']) # Bob assesses Tim. peer_api.get_submission_to_assess(submission['uuid'], 1) peer_api.create_assessment( submission["uuid"], STUDENT_ITEM["student_id"], ASSESSMENT_DICT['options_selected'], dict(), "", {'criteria': xblock.rubric_criteria}, 1, ) # Bob assesses himself. self_api.create_assessment( submission['uuid'], STUDENT_ITEM["student_id"], ASSESSMENT_DICT['options_selected'], {'criteria': xblock.rubric_criteria}, ) # Now Bob should be fully populated in the student info view. request = namedtuple('Request', 'params') request.params = {"student_id": "Bob"} # Verify that we can render without error resp = xblock.render_student_info(request) self.assertIn("bob answer", resp.body.lower())
def _submit_peer_assessment(self, xblock, student_id, scorer_id, assessment, expect_failure=False): """ Create submissions for a student and scorer, then create a peer assessment from the scorer. Args: xblock (OpenAssessmentBlock) student_id (unicode): The ID of the student being assessed. scorer_id (unicode): The ID of the student creating the assessment. assessment (dict): Serialized assessment model. Keyword Arguments: expect_failure (bool): If true, expect a failure response and return None Returns: dict: The peer assessment retrieved from the API. """ # Create a submission for this problem from another user student_item = xblock.get_student_item_dict() student_item["student_id"] = student_id submission = xblock.create_submission(student_item, self.SUBMISSION) # Create a submission for the scorer (required before assessing another student) another_student = copy.deepcopy(student_item) another_student["student_id"] = scorer_id another_submission = xblock.create_submission(another_student, self.SUBMISSION) # Pull the submission to assess peer_api.get_submission_to_assess(another_submission["uuid"], 3) # Submit an assessment and expect a successful response assessment = copy.deepcopy(assessment) assessment["submission_uuid"] = assessment.get("submission_uuid", submission.get("uuid", None)) resp = self.request(xblock, "peer_assess", json.dumps(assessment), response_format="json") if expect_failure: self.assertFalse(resp["success"]) return None else: self.assertTrue(resp["success"]) # Retrieve the peer assessment retrieved_assessment = peer_api.get_assessments(submission["uuid"], scored_only=False)[0] return submission["uuid"], retrieved_assessment
def test_get_submitted_assessments(self): self._create_student_and_submission("Tim", "Tim's answer") bob_sub, bob = self._create_student_and_submission("Bob", "Bob's answer") peer_api.get_submission_to_assess(bob_sub['uuid'], REQUIRED_GRADED_BY) assessment = peer_api.create_assessment( bob_sub["uuid"], bob["student_id"], ASSESSMENT_DICT['options_selected'], dict(), "", RUBRIC_DICT, REQUIRED_GRADED_BY, ) self.assertEqual(assessment["points_earned"], 6) self.assertEqual(assessment["points_possible"], 14) submitted_assessments = peer_api.get_submitted_assessments(bob_sub["uuid"], scored_only=True) self.assertEqual(0, len(submitted_assessments)) submitted_assessments = peer_api.get_submitted_assessments(bob_sub["uuid"], scored_only=False) self.assertEqual(1, len(submitted_assessments))
def test_staff_area_student_info_peer_only(self, xblock): # Simulate that we are course staff xblock.xmodule_runtime = self._create_mock_runtime( xblock.scope_ids.usage_id, True, False, "Bob") xblock.runtime._services['user'] = NullUserService() bob_item = STUDENT_ITEM.copy() bob_item["item_id"] = xblock.scope_ids.usage_id # Create a submission for Bob, and corresponding workflow. submission = self._create_submission( bob_item, prepare_submission_for_serialization( ("Bob Answer 1", "Bob Answer 2")), ['peer']) # Create a submission for Tim, and corresponding workflow. tim_item = bob_item.copy() tim_item["student_id"] = "Tim" self._create_submission(tim_item, "Tim Answer", ['peer', 'self']) # Bob assesses Tim. peer_api.get_submission_to_assess(submission['uuid'], 1) peer_api.create_assessment( submission["uuid"], STUDENT_ITEM["student_id"], ASSESSMENT_DICT['options_selected'], dict(), "", {'criteria': xblock.rubric_criteria}, 1, ) # Now Bob should be fully populated in the student info view. path, context = xblock.get_student_info_path_and_context("Bob") self.assertEquals("Bob Answer 1", context['submission']['answer']['parts'][0]['text']) self.assertIsNotNone(context['peer_assessments']) self.assertIsNone(context['self_assessment']) self.assertIsNone(context['staff_assessment']) self.assertEquals( "openassessmentblock/staff_area/oa_student_info.html", path) # Bob still needs to assess other learners self.assertIsNone(context['grade_details'])
def test_create_assessment_unknown_criterion_feedback(self): self._create_student_and_submission("Tim", "Tim's answer") bob_sub, bob = self._create_student_and_submission("Bob", "Bob's answer") peer_api.get_submission_to_assess(bob_sub['uuid'], 1) # Create an assessment where the criterion feedback uses # a criterion name that isn't in the rubric. assessment = peer_api.create_assessment( bob_sub["uuid"], bob["student_id"], ASSESSMENT_DICT['options_selected'], {'unknown': 'Unknown criterion has feedback!'}, ASSESSMENT_DICT['overall_feedback'], RUBRIC_DICT, REQUIRED_GRADED_BY, ) # The criterion feedback should be ignored for part_num in range(3): self.assertEqual(assessment["parts"][part_num]["feedback"], "")
def _sally_and_hal_grade_each_other_helper(self, xblock): """ A helper method to set up 2 submissions, one for each of Sally and Hal, and then have each assess the other. """ student_item = xblock.get_student_item_dict() # Sally submits a response. sally_student_item = copy.deepcopy(student_item) sally_student_item['student_id'] = "Sally" sally_submission = xblock.create_submission(sally_student_item, (u"Sally's answer 1", u"Sally's answer 2")) # Hal comes and submits a response. hal_student_item = copy.deepcopy(student_item) hal_student_item['student_id'] = "Hal" hal_submission = xblock.create_submission(hal_student_item, (u"Hal's answer 1", u"Hal's answer 2")) # Now Hal will assess Sally. assessment = copy.deepcopy(self.ASSESSMENT) peer_api.get_submission_to_assess(hal_submission['uuid'], 1) peer_api.create_assessment( hal_submission['uuid'], hal_student_item['student_id'], assessment['options_selected'], assessment['criterion_feedback'], assessment['overall_feedback'], {'criteria': xblock.rubric_criteria}, 1 ) # Now Sally will assess Hal. assessment = copy.deepcopy(self.ASSESSMENT) peer_api.get_submission_to_assess(sally_submission['uuid'], 1) peer_api.create_assessment( sally_submission['uuid'], sally_student_item['student_id'], assessment['options_selected'], assessment['criterion_feedback'], assessment['overall_feedback'], {'criteria': xblock.rubric_criteria}, 1 )
def _sally_and_hal_grade_each_other_helper(self, xblock): """ A helper method to set up 2 submissions, one for each of Sally and Hal, and then have each assess the other. """ student_item = xblock.get_student_item_dict() # Sally submits a response. sally_student_item = copy.deepcopy(student_item) sally_student_item["student_id"] = "Sally" sally_submission = xblock.create_submission(sally_student_item, (u"Sally's answer 1", u"Sally's answer 2")) # Hal comes and submits a response. hal_student_item = copy.deepcopy(student_item) hal_student_item["student_id"] = "Hal" hal_submission = xblock.create_submission(hal_student_item, (u"Hal's answer 1", u"Hal's answer 2")) # Now Hal will assess Sally. assessment = copy.deepcopy(self.ASSESSMENT) peer_api.get_submission_to_assess(hal_submission["uuid"], 1) peer_api.create_assessment( hal_submission["uuid"], hal_student_item["student_id"], assessment["options_selected"], assessment["criterion_feedback"], assessment["overall_feedback"], {"criteria": xblock.rubric_criteria}, 1, ) # Now Sally will assess Hal. assessment = copy.deepcopy(self.ASSESSMENT) peer_api.get_submission_to_assess(sally_submission["uuid"], 1) peer_api.create_assessment( sally_submission["uuid"], sally_student_item["student_id"], assessment["options_selected"], assessment["criterion_feedback"], assessment["overall_feedback"], {"criteria": xblock.rubric_criteria}, 1, )
def test_peer_leases_same_submission(self): """ Tests the scenario where a student pulls a peer's submission for assessment, lets the lease expire, then pulls the same peer's submission a second time. This creates two similar PeerWorkflowItems in the database, and when completing the assessment, the latest PeerWorkflowItem should be updated. """ yesterday = timezone.now() - datetime.timedelta(days=1) tim_sub, tim = self._create_student_and_submission("Tim", "Tim's answer") self._create_student_and_submission("Bob", "Bob's answer") self._create_student_and_submission("Sally", "Sally's answer") sub = peer_api.get_submission_to_assess(tim_sub['uuid'], REQUIRED_GRADED) self.assertEqual(u"Bob's answer", sub['answer']) # And now we cheat; we want to set the clock back such that the lease # on this PeerWorkflowItem has expired. pwis = PeerWorkflowItem.objects.filter(submission_uuid=sub['uuid']) self.assertEqual(len(pwis), 1) pwis[0].started_at = yesterday pwis[0].save() sub = peer_api.get_submission_to_assess(tim_sub['uuid'], REQUIRED_GRADED) self.assertEqual(u"Bob's answer", sub['answer']) peer_api.create_assessment( tim_sub["uuid"], tim["student_id"], ASSESSMENT_DICT['options_selected'], ASSESSMENT_DICT['criterion_feedback'], ASSESSMENT_DICT['overall_feedback'], RUBRIC_DICT, REQUIRED_GRADED_BY, ) pwis = PeerWorkflowItem.objects.filter(submission_uuid=sub['uuid']) self.assertEqual(len(pwis), 1) self.assertNotEqual(pwis[0].started_at, yesterday)
def test_get_submission_to_evaluate(self): submission, __ = self._create_student_and_submission("Tim", "Tim's answer", MONDAY) self._create_student_and_submission("Bob", "Bob's answer", TUESDAY) self._create_student_and_submission( "Sally", "Sally's answer", WEDNESDAY ) self._create_student_and_submission("Jim", "Jim's answer", THURSDAY) submission = peer_api.get_submission_to_assess(submission['uuid'], 3) self.assertIsNotNone(submission) self.assertEqual(submission["answer"], u"Bob's answer") self.assertEqual(submission["student_item"], 2) self.assertEqual(submission["attempt_number"], 1)
def test_staff_area_student_info_peer_only(self, xblock): # Simulate that we are course staff xblock.xmodule_runtime = self._create_mock_runtime( xblock.scope_ids.usage_id, True, False, "Bob" ) xblock.runtime._services['user'] = NullUserService() bob_item = STUDENT_ITEM.copy() bob_item["item_id"] = xblock.scope_ids.usage_id # Create a submission for Bob, and corresponding workflow. submission = self._create_submission( bob_item, prepare_submission_for_serialization(("Bob Answer 1", "Bob Answer 2")), ['peer'] ) # Create a submission for Tim, and corresponding workflow. tim_item = bob_item.copy() tim_item["student_id"] = "Tim" self._create_submission(tim_item, "Tim Answer", ['peer', 'self']) # Bob assesses Tim. peer_api.get_submission_to_assess(submission['uuid'], 1) peer_api.create_assessment( submission["uuid"], STUDENT_ITEM["student_id"], ASSESSMENT_DICT['options_selected'], dict(), "", {'criteria': xblock.rubric_criteria}, 1, ) # Now Bob should be fully populated in the student info view. path, context = xblock.get_student_info_path_and_context("Bob") self.assertEquals("Bob Answer 1", context['submission']['answer']['parts'][0]['text']) self.assertIsNotNone(context['peer_assessments']) self.assertIsNone(context['self_assessment']) self.assertIsNone(context['staff_assessment']) self.assertEquals("openassessmentblock/staff_area/oa_student_info.html", path) # Bob still needs to assess other learners self.assertIsNone(context['grade_details'])
def test_create_huge_per_criterion_feedback_error(self): self._create_student_and_submission("Tim", "Tim's answer") bob_sub, bob = self._create_student_and_submission("Bob", "Bob's answer") peer_api.get_submission_to_assess(bob_sub['uuid'], 1) # Huge per-criterion feedback text assessment = peer_api.create_assessment( bob_sub["uuid"], bob["student_id"], ASSESSMENT_DICT_HUGE['options_selected'], ASSESSMENT_DICT_HUGE['criterion_feedback'], "", RUBRIC_DICT, REQUIRED_GRADED_BY, ) # Verify that the feedback has been truncated for part in assessment['parts']: self.assertEqual(len(part['feedback']), Assessment.MAXSIZE) # Verify that the feedback in the database matches what we got back from the API for part in AssessmentPart.objects.all(): self.assertEqual(len(part.feedback), Assessment.MAXSIZE)
def test_create_huge_overall_feedback_error(self): self._create_student_and_submission("Tim", "Tim's answer") bob_sub, bob = self._create_student_and_submission("Bob", "Bob's answer") peer_api.get_submission_to_assess(bob_sub['uuid'], 1) # Huge overall feedback text assessment_dict = peer_api.create_assessment( bob_sub["uuid"], bob["student_id"], ASSESSMENT_DICT_HUGE['options_selected'], dict(), ASSESSMENT_DICT_HUGE['overall_feedback'], RUBRIC_DICT, REQUIRED_GRADED_BY, ) # The assessment feedback text should be truncated self.assertEqual(len(assessment_dict['feedback']), Assessment.MAXSIZE) # The length of the feedback text in the database should # equal what we got from the API. assessment = Assessment.objects.get() self.assertEqual(len(assessment.feedback), Assessment.MAXSIZE)
def test_peer_assess_for_already_cancelled_submission(self, xblock): # Create a submission for this problem from another user student_item = xblock.get_student_item_dict() submission = xblock.create_submission(student_item, self.SUBMISSION) # Create a submission for the scorer (required before assessing another student) another_student = copy.deepcopy(student_item) another_submission = xblock.create_submission(another_student, self.SUBMISSION) assessment = self.ASSESSMENT assessment['submission_uuid'] = assessment.get( 'submission_uuid', submission.get('uuid', None)) # Pull the submission to assess peer_api.get_submission_to_assess(another_submission['uuid'], 3) requirements = { "peer": { "must_grade": 1, "must_be_graded_by": 1 }, } workflow_api.cancel_workflow( submission_uuid=submission['uuid'], comments="Inappropriate language", cancelled_by_id=another_student['student_id'], assessment_requirements=requirements) # Submit an assessment and expect a failure resp = self.request(xblock, 'peer_assess', json.dumps(assessment), response_format='json') self.assertEqual(resp['success'], False) self.assertGreater(len(resp['msg']), 0)
def test_get_assessments(self, assessment_dict): self._create_student_and_submission("Tim", "Tim's answer") bob_sub, bob = self._create_student_and_submission("Bob", "Bob's answer") sub = peer_api.get_submission_to_assess(bob_sub['uuid'], 3) peer_api.create_assessment( bob_sub["uuid"], bob["student_id"], assessment_dict['options_selected'], assessment_dict['criterion_feedback'], assessment_dict['overall_feedback'], RUBRIC_DICT, REQUIRED_GRADED_BY, ) assessments = peer_api.get_assessments(sub["uuid"], scored_only=False) self.assertEqual(1, len(assessments))
def test_error_on_get_assessment(self, mock_filter): self._create_student_and_submission("Tim", "Tim's answer") bob_sub, bob = self._create_student_and_submission("Bob", "Bob's answer") sub = peer_api.get_submission_to_assess(bob_sub['uuid'], 3) peer_api.create_assessment( bob_sub["uuid"], bob["student_id"], ASSESSMENT_DICT['options_selected'], ASSESSMENT_DICT['criterion_feedback'], ASSESSMENT_DICT['overall_feedback'], RUBRIC_DICT, REQUIRED_GRADED_BY, MONDAY, ) mock_filter.side_effect = DatabaseError("Bad things happened") peer_api.get_assessments(sub["uuid"])
def test_get_max_scores(self): self._create_student_and_submission("Tim", "Tim's answer") bob_sub, bob = self._create_student_and_submission("Bob", "Bob's answer") sub = peer_api.get_submission_to_assess(bob_sub['uuid'], 1) assessment = peer_api.create_assessment( bob_sub["uuid"], bob["student_id"], ASSESSMENT_DICT['options_selected'], ASSESSMENT_DICT['criterion_feedback'], ASSESSMENT_DICT['overall_feedback'], RUBRIC_DICT, 1 ) max_scores = peer_api.get_rubric_max_scores(sub["uuid"]) self.assertEqual(max_scores['secret'], 1) self.assertEqual(max_scores['giveup'], 10)
def test_has_finished_evaluation(self): """ Verify unfinished assessments do not get counted when determining a complete workflow. """ tim_sub, _ = self._create_student_and_submission("Tim", "Tim's answer") bob_sub, bob = self._create_student_and_submission("Bob", "Bob's answer") sub = peer_api.get_submission_to_assess(bob_sub['uuid'], 1) self.assertEqual(sub["uuid"], tim_sub["uuid"]) finished, count = peer_api.has_finished_required_evaluating(bob_sub['uuid'], 1) self.assertFalse(finished) self.assertEqual(count, 0) peer_api.create_assessment( bob_sub["uuid"], bob["student_id"], ASSESSMENT_DICT['options_selected'], ASSESSMENT_DICT['criterion_feedback'], ASSESSMENT_DICT['overall_feedback'], RUBRIC_DICT, 1, ) finished, count = peer_api.has_finished_required_evaluating(bob_sub['uuid'], 1) self.assertTrue(finished) self.assertEqual(count, 1)
def _create_submission_and_assessments( self, xblock, submission_text, peers, peer_assessments, self_assessment, waiting_for_peer=False, ): """ Create a submission and peer/self assessments, so that the user can receive a grade. Args: xblock (OpenAssessmentBlock): The XBlock, loaded for the user who needs a grade. submission_text (unicode): Text of the submission from the user. peers (list of unicode): List of user IDs of peers who will assess the user. peer_assessments (list of dict): List of assessment dictionaries for peer assessments. self_assessment (dict): Dict of assessment for self-assessment. Keyword Arguments: waiting_for_peer (bool): If true, skip creation of peer assessments for the user's submission. Returns: None """ # Create a submission from the user student_item = xblock.get_student_item_dict() student_id = student_item['student_id'] submission = xblock.create_submission(student_item, submission_text) # Create submissions and assessments from other users scorer_submissions = [] for scorer_name, assessment in zip(peers, peer_assessments): # Create a submission for each scorer for the same problem scorer = copy.deepcopy(student_item) scorer['student_id'] = scorer_name scorer_sub = sub_api.create_submission(scorer, {'text': submission_text}) workflow_api.create_workflow(scorer_sub['uuid'], self.STEPS) submission = peer_api.get_submission_to_assess( scorer_sub['uuid'], len(peers)) # Store the scorer's submission so our user can assess it later scorer_submissions.append(scorer_sub) # Create an assessment of the user's submission if not waiting_for_peer: peer_api.create_assessment( scorer_sub['uuid'], scorer_name, assessment['options_selected'], assessment['criterion_feedback'], assessment['overall_feedback'], {'criteria': xblock.rubric_criteria}, xblock.get_assessment_module( 'peer-assessment')['must_be_graded_by']) # Have our user make assessments (so she can get a score) for asmnt in peer_assessments: peer_api.get_submission_to_assess(submission['uuid'], len(peers)) peer_api.create_assessment( submission['uuid'], student_id, asmnt['options_selected'], asmnt['criterion_feedback'], asmnt['overall_feedback'], {'criteria': xblock.rubric_criteria}, xblock.get_assessment_module( 'peer-assessment')['must_be_graded_by']) # Have the user submit a self-assessment (so she can get a score) if self_assessment is not None: self_api.create_assessment(submission['uuid'], student_id, self_assessment['options_selected'], self_assessment['criterion_feedback'], self_assessment['overall_feedback'], {'criteria': xblock.rubric_criteria})
def _peer_assess(sub, scorer_id, scores): bob_sub, bob = TestStaffAssessment._create_student_and_submission("Bob", "Bob's answer", problem_steps=['peer']) peer_api.get_submission_to_assess(bob_sub["uuid"], 1) return peer_assess(bob_sub["uuid"], bob["student_id"], scores, dict(), "", RUBRIC, 1)
def _create_submission_and_assessments( self, xblock, submission_text, peers, peer_assessments, self_assessment, waiting_for_peer=False, ): """ Create a submission and peer/self assessments, so that the user can receive a grade. Args: xblock (OpenAssessmentBlock): The XBlock, loaded for the user who needs a grade. submission_text (unicode): Text of the submission from the user. peers (list of unicode): List of user IDs of peers who will assess the user. peer_assessments (list of dict): List of assessment dictionaries for peer assessments. self_assessment (dict): Dict of assessment for self-assessment. Keyword Arguments: waiting_for_peer (bool): If true, skip creation of peer assessments for the user's submission. Returns: None """ # Create a submission from the user student_item = xblock.get_student_item_dict() student_id = student_item['student_id'] submission = xblock.create_submission(student_item, submission_text) # Create submissions and assessments from other users scorer_submissions = [] for scorer_name, assessment in zip(peers, peer_assessments): # Create a submission for each scorer for the same problem scorer = copy.deepcopy(student_item) scorer['student_id'] = scorer_name scorer_sub = sub_api.create_submission(scorer, {'text': submission_text}) workflow_api.create_workflow(scorer_sub['uuid'], self.STEPS) submission = peer_api.get_submission_to_assess(scorer_sub['uuid'], len(peers)) # Store the scorer's submission so our user can assess it later scorer_submissions.append(scorer_sub) # Create an assessment of the user's submission if not waiting_for_peer: peer_api.create_assessment( scorer_sub['uuid'], scorer_name, assessment['options_selected'], assessment['criterion_feedback'], assessment['overall_feedback'], {'criteria': xblock.rubric_criteria}, xblock.get_assessment_module('peer-assessment')['must_be_graded_by'] ) # Have our user make assessments (so she can get a score) for asmnt in peer_assessments: peer_api.get_submission_to_assess(submission['uuid'], len(peers)) peer_api.create_assessment( submission['uuid'], student_id, asmnt['options_selected'], asmnt['criterion_feedback'], asmnt['overall_feedback'], {'criteria': xblock.rubric_criteria}, xblock.get_assessment_module('peer-assessment')['must_be_graded_by'] ) # Have the user submit a self-assessment (so she can get a score) if self_assessment is not None: self_api.create_assessment( submission['uuid'], student_id, self_assessment['options_selected'], self_assessment['criterion_feedback'], self_assessment['overall_feedback'], {'criteria': xblock.rubric_criteria} )
def test_turbo_grading(self, xblock): student_item = xblock.get_student_item_dict() sally_student_item = copy.deepcopy(student_item) sally_student_item['student_id'] = "Sally" sally_submission = xblock.create_submission(sally_student_item, u"Sally's answer") # Hal comes and submits a response. hal_student_item = copy.deepcopy(student_item) hal_student_item['student_id'] = "Hal" hal_submission = xblock.create_submission(hal_student_item, u"Hal's answer") # Now Hal will assess Sally. assessment = copy.deepcopy(self.ASSESSMENT) sally_sub = peer_api.get_submission_to_assess(hal_submission['uuid'], 1) assessment['submission_uuid'] = sally_sub['uuid'] peer_api.create_assessment( hal_submission['uuid'], hal_student_item['student_id'], assessment['options_selected'], assessment['criterion_feedback'], assessment['overall_feedback'], {'criteria': xblock.rubric_criteria}, 1 ) # Now Sally will assess Hal. assessment = copy.deepcopy(self.ASSESSMENT) hal_sub = peer_api.get_submission_to_assess(sally_submission['uuid'], 1) assessment['submission_uuid'] = hal_sub['uuid'] peer_api.create_assessment( sally_submission['uuid'], sally_student_item['student_id'], assessment['options_selected'], assessment['criterion_feedback'], assessment['overall_feedback'], {'criteria': xblock.rubric_criteria}, 1 ) # If Over Grading is on, this should now return Sally's response to Bob. submission = xblock.create_submission(student_item, u"Bob's answer") workflow_info = xblock.get_workflow_info() self.assertEqual(workflow_info["status"], u'peer') # Validate Submission Rendering. request = namedtuple('Request', 'params') request.params = {'continue_grading': True} peer_response = xblock.render_peer_assessment(request) self.assertIsNotNone(peer_response) self.assertNotIn(submission["answer"]["text"].encode('utf-8'), peer_response.body) peer_api.create_assessment( submission['uuid'], student_item['student_id'], assessment['options_selected'], assessment['criterion_feedback'], assessment['overall_feedback'], {'criteria': xblock.rubric_criteria}, 1 ) # Validate Submission Rendering. request = namedtuple('Request', 'params') request.params = {'continue_grading': True} peer_response = xblock.render_peer_assessment(request) self.assertIsNotNone(peer_response) self.assertNotIn(submission["answer"]["text"].encode('utf-8'), peer_response.body) peer_api.create_assessment( submission['uuid'], student_item['student_id'], assessment['options_selected'], assessment['criterion_feedback'], assessment['overall_feedback'], {'criteria': xblock.rubric_criteria}, 1 ) # A Final over grading will not return anything. request = namedtuple('Request', 'params') request.params = {'continue_grading': True} peer_response = xblock.render_peer_assessment(request) self.assertIsNotNone(peer_response) self.assertNotIn(submission["answer"]["text"].encode('utf-8'), peer_response.body) self.assertIn("Peer Assessments Complete", peer_response.body)
def _peer_assess(sub, scorer_id, scores): bob_sub, bob = TestStaffAssessment._create_student_and_submission( "Bob", "Bob's answer", problem_steps=['peer']) peer_api.get_submission_to_assess(bob_sub["uuid"], 1) return peer_assess(bob_sub["uuid"], bob["student_id"], scores, dict(), "", RUBRIC, 1)
def test_turbo_grading(self, xblock): student_item = xblock.get_student_item_dict() sally_student_item = copy.deepcopy(student_item) sally_student_item['student_id'] = "Sally" sally_submission = xblock.create_submission(sally_student_item, u"Sally's answer") # Hal comes and submits a response. hal_student_item = copy.deepcopy(student_item) hal_student_item['student_id'] = "Hal" hal_submission = xblock.create_submission(hal_student_item, u"Hal's answer") # Now Hal will assess Sally. assessment = copy.deepcopy(self.ASSESSMENT) sally_sub = peer_api.get_submission_to_assess(hal_submission['uuid'], 1) assessment['submission_uuid'] = sally_sub['uuid'] peer_api.create_assessment(hal_submission['uuid'], hal_student_item['student_id'], assessment['options_selected'], assessment['criterion_feedback'], assessment['overall_feedback'], {'criteria': xblock.rubric_criteria}, 1) # Now Sally will assess Hal. assessment = copy.deepcopy(self.ASSESSMENT) hal_sub = peer_api.get_submission_to_assess(sally_submission['uuid'], 1) assessment['submission_uuid'] = hal_sub['uuid'] peer_api.create_assessment(sally_submission['uuid'], sally_student_item['student_id'], assessment['options_selected'], assessment['criterion_feedback'], assessment['overall_feedback'], {'criteria': xblock.rubric_criteria}, 1) # If Over Grading is on, this should now return Sally's response to Bob. submission = xblock.create_submission(student_item, u"Bob's answer") workflow_info = xblock.get_workflow_info() self.assertEqual(workflow_info["status"], u'peer') # Validate Submission Rendering. request = namedtuple('Request', 'params') request.params = {'continue_grading': True} peer_response = xblock.render_peer_assessment(request) self.assertIsNotNone(peer_response) self.assertNotIn(submission["answer"]["text"].encode('utf-8'), peer_response.body) peer_api.create_assessment(submission['uuid'], student_item['student_id'], assessment['options_selected'], assessment['criterion_feedback'], assessment['overall_feedback'], {'criteria': xblock.rubric_criteria}, 1) # Validate Submission Rendering. request = namedtuple('Request', 'params') request.params = {'continue_grading': True} peer_response = xblock.render_peer_assessment(request) self.assertIsNotNone(peer_response) self.assertNotIn(submission["answer"]["text"].encode('utf-8'), peer_response.body) peer_api.create_assessment(submission['uuid'], student_item['student_id'], assessment['options_selected'], assessment['criterion_feedback'], assessment['overall_feedback'], {'criteria': xblock.rubric_criteria}, 1) # A Final over grading will not return anything. request = namedtuple('Request', 'params') request.params = {'continue_grading': True} peer_response = xblock.render_peer_assessment(request) self.assertIsNotNone(peer_response) self.assertNotIn(submission["answer"]["text"].encode('utf-8'), peer_response.body) self.assertIn("Peer Assessments Complete", peer_response.body)