class OpenEndedModuleTest(unittest.TestCase): """ Test the open ended module class """ location = Location(["i4x", "edX", "sa_test", "selfassessment", "SampleQuestion"]) metadata = json.dumps({'attempts': '10'}) prompt = etree.XML("<prompt>This is a question prompt</prompt>") rubric = etree.XML('''<rubric> <category> <description>Response Quality</description> <option>The response is not a satisfactory answer to the question. It either fails to address the question or does so in a limited way, with no evidence of higher-order thinking.</option> </category> </rubric>''') max_score = 4 static_data = { 'max_attempts': 20, 'prompt': prompt, 'rubric': rubric, 'max_score': max_score, 'display_name': 'Name', 'accept_file_upload': False, 'close_date': None, 's3_interface': test_util_open_ended.S3_INTERFACE, 'open_ended_grading_interface': test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE, 'skip_basic_checks': False, 'control': { 'required_peer_grading': 1, 'peer_grader_count': 1, 'min_to_calibrate': 3, 'max_to_calibrate': 6, 'peer_grade_finished_submissions_when_none_pending': False, } } oeparam = etree.XML(''' <openendedparam> <initial_display>Enter essay here.</initial_display> <answer_display>This is the answer.</answer_display> <grader_payload>{"grader_settings" : "ml_grading.conf", "problem_id" : "6.002x/Welcome/OETest"}</grader_payload> </openendedparam> ''') definition = {'oeparam': oeparam} descriptor = Mock() def setUp(self): self.test_system = get_test_system() self.test_system.open_ended_grading_interface = None self.test_system.location = self.location self.mock_xqueue = MagicMock() self.mock_xqueue.send_to_queue.return_value = (None, "Message") def constructed_callback(dispatch="score_update"): return dispatch self.test_system.xqueue = {'interface': self.mock_xqueue, 'construct_callback': constructed_callback, 'default_queuename': 'testqueue', 'waittime': 1} self.openendedmodule = OpenEndedModule(self.test_system, self.location, self.definition, self.descriptor, self.static_data, self.metadata) def test_message_post(self): get = {'feedback': 'feedback text', 'submission_id': '1', 'grader_id': '1', 'score': 3} qtime = datetime.strftime(datetime.now(UTC), xqueue_interface.dateformat) student_info = {'anonymous_student_id': self.test_system.anonymous_student_id, 'submission_time': qtime} contents = { 'feedback': get['feedback'], 'submission_id': int(get['submission_id']), 'grader_id': int(get['grader_id']), 'score': get['score'], 'student_info': json.dumps(student_info) } result = self.openendedmodule.message_post(get, self.test_system) self.assertTrue(result['success']) # make sure it's actually sending something we want to the queue self.mock_xqueue.send_to_queue.assert_called_with(body=json.dumps(contents), header=ANY) state = json.loads(self.openendedmodule.get_instance_state()) self.assertIsNotNone(state['child_state'], OpenEndedModule.DONE) def test_send_to_grader(self): submission = "This is a student submission" qtime = datetime.strftime(datetime.now(UTC), xqueue_interface.dateformat) student_info = {'anonymous_student_id': self.test_system.anonymous_student_id, 'submission_time': qtime} contents = self.openendedmodule.payload.copy() contents.update({ 'student_info': json.dumps(student_info), 'student_response': submission, 'max_score': self.max_score }) result = self.openendedmodule.send_to_grader(submission, self.test_system) self.assertTrue(result) self.mock_xqueue.send_to_queue.assert_called_with(body=json.dumps(contents), header=ANY) def update_score_single(self): self.openendedmodule.new_history_entry("New Entry") score_msg = { 'correct': True, 'score': 4, 'msg': 'Grader Message', 'feedback': "Grader Feedback" } get = {'queuekey': "abcd", 'xqueue_body': score_msg} self.openendedmodule.update_score(get, self.test_system) def update_score_single(self): self.openendedmodule.new_history_entry("New Entry") feedback = { "success": True, "feedback": "Grader Feedback" } score_msg = { 'correct': True, 'score': 4, 'msg': 'Grader Message', 'feedback': json.dumps(feedback), 'grader_type': 'IN', 'grader_id': '1', 'submission_id': '1', 'success': True, 'rubric_scores': [0], 'rubric_scores_complete': True, 'rubric_xml': etree.tostring(self.rubric) } get = {'queuekey': "abcd", 'xqueue_body': json.dumps(score_msg)} self.openendedmodule.update_score(get, self.test_system) def update_score_multiple(self): self.openendedmodule.new_history_entry("New Entry") feedback = { "success": True, "feedback": "Grader Feedback" } score_msg = { 'correct': True, 'score': [0, 1], 'msg': 'Grader Message', 'feedback': [json.dumps(feedback), json.dumps(feedback)], 'grader_type': 'PE', 'grader_id': ['1', '2'], 'submission_id': '1', 'success': True, 'rubric_scores': [[0], [0]], 'rubric_scores_complete': [True, True], 'rubric_xml': [etree.tostring(self.rubric), etree.tostring(self.rubric)] } get = {'queuekey': "abcd", 'xqueue_body': json.dumps(score_msg)} self.openendedmodule.update_score(get, self.test_system) def test_latest_post_assessment(self): self.update_score_single() assessment = self.openendedmodule.latest_post_assessment(self.test_system) self.assertFalse(assessment == '') # check for errors self.assertFalse('errors' in assessment) def test_update_score_single(self): self.update_score_single() score = self.openendedmodule.latest_score() self.assertEqual(score, 4) def test_update_score_multiple(self): """ Tests that a score of [0, 1] gets aggregated to 1. A change in behavior added by @jbau """ self.update_score_multiple() score = self.openendedmodule.latest_score() self.assertEquals(score, 1) def test_open_ended_display(self): """ Test storing answer with the open ended module. """ # Create a module with no state yet. Important that this start off as a blank slate. test_module = OpenEndedModule(self.test_system, self.location, self.definition, self.descriptor, self.static_data, self.metadata) saved_response = "Saved response." submitted_response = "Submitted response." # Initially, there will be no stored answer. self.assertEqual(test_module.stored_answer, None) # And the initial answer to display will be an empty string. self.assertEqual(test_module.get_display_answer(), "") # Now, store an answer in the module. test_module.handle_ajax("store_answer", {'student_answer' : saved_response}, get_test_system()) # The stored answer should now equal our response. self.assertEqual(test_module.stored_answer, saved_response) self.assertEqual(test_module.get_display_answer(), saved_response) # Mock out the send_to_grader function so it doesn't try to connect to the xqueue. test_module.send_to_grader = Mock(return_value=True) # Submit a student response to the question. test_module.handle_ajax( "save_answer", {"student_answer": submitted_response}, get_test_system() ) # Submitting an answer should clear the stored answer. self.assertEqual(test_module.stored_answer, None) # Confirm that the answer is stored properly. self.assertEqual(test_module.latest_answer(), submitted_response)
class OpenEndedModuleTest(unittest.TestCase): """ Test the open ended module class """ location = Location( ["i4x", "edX", "sa_test", "selfassessment", "SampleQuestion"]) metadata = json.dumps({'attempts': '10'}) prompt = etree.XML("<prompt>This is a question prompt</prompt>") rubric = etree.XML('''<rubric> <category> <description>Response Quality</description> <option>The response is not a satisfactory answer to the question. It either fails to address the question or does so in a limited way, with no evidence of higher-order thinking.</option> </category> </rubric>''') max_score = 4 static_data = { 'max_attempts': 20, 'prompt': prompt, 'rubric': rubric, 'max_score': max_score, 'display_name': 'Name', 'accept_file_upload': False, 'close_date': None, 's3_interface': test_util_open_ended.S3_INTERFACE, 'open_ended_grading_interface': test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE, 'skip_basic_checks': False, 'control': { 'required_peer_grading': 1, 'peer_grader_count': 1, 'min_to_calibrate': 3, 'max_to_calibrate': 6, 'peer_grade_finished_submissions_when_none_pending': False, } } oeparam = etree.XML(''' <openendedparam> <initial_display>Enter essay here.</initial_display> <answer_display>This is the answer.</answer_display> <grader_payload>{"grader_settings" : "ml_grading.conf", "problem_id" : "6.002x/Welcome/OETest"}</grader_payload> </openendedparam> ''') definition = {'oeparam': oeparam} descriptor = Mock() feedback = {"success": True, "feedback": "Grader Feedback"} single_score_msg = { 'correct': True, 'score': 4, 'msg': 'Grader Message', 'feedback': json.dumps(feedback), 'grader_type': 'IN', 'grader_id': '1', 'submission_id': '1', 'success': True, 'rubric_scores': [0], 'rubric_scores_complete': True, 'rubric_xml': etree.tostring(rubric) } multiple_score_msg = { 'correct': True, 'score': [0, 1], 'msg': 'Grader Message', 'feedback': [json.dumps(feedback), json.dumps(feedback)], 'grader_type': 'PE', 'grader_id': ['1', '2'], 'submission_id': '1', 'success': True, 'rubric_scores': [[0], [0]], 'rubric_scores_complete': [True, True], 'rubric_xml': [etree.tostring(rubric), etree.tostring(rubric)] } def setUp(self): self.test_system = get_test_system() self.test_system.open_ended_grading_interface = None self.test_system.location = self.location self.mock_xqueue = MagicMock() self.mock_xqueue.send_to_queue.return_value = (None, "Message") def constructed_callback(dispatch="score_update"): return dispatch self.test_system.xqueue = { 'interface': self.mock_xqueue, 'construct_callback': constructed_callback, 'default_queuename': 'testqueue', 'waittime': 1 } self.openendedmodule = OpenEndedModule(self.test_system, self.location, self.definition, self.descriptor, self.static_data, self.metadata) def test_message_post(self): get = { 'feedback': 'feedback text', 'submission_id': '1', 'grader_id': '1', 'score': 3 } qtime = datetime.strftime(datetime.now(UTC), xqueue_interface.dateformat) student_info = { 'anonymous_student_id': self.test_system.anonymous_student_id, 'submission_time': qtime } contents = { 'feedback': get['feedback'], 'submission_id': int(get['submission_id']), 'grader_id': int(get['grader_id']), 'score': get['score'], 'student_info': json.dumps(student_info) } result = self.openendedmodule.message_post(get, self.test_system) self.assertTrue(result['success']) # make sure it's actually sending something we want to the queue self.mock_xqueue.send_to_queue.assert_called_with( body=json.dumps(contents), header=ANY) state = json.loads(self.openendedmodule.get_instance_state()) self.assertIsNotNone(state['child_state'], OpenEndedModule.DONE) def test_send_to_grader(self): submission = "This is a student submission" qtime = datetime.strftime(datetime.now(UTC), xqueue_interface.dateformat) student_info = { 'anonymous_student_id': self.test_system.anonymous_student_id, 'submission_time': qtime } contents = self.openendedmodule.payload.copy() contents.update({ 'student_info': json.dumps(student_info), 'student_response': submission, 'max_score': self.max_score }) result = self.openendedmodule.send_to_grader(submission, self.test_system) self.assertTrue(result) self.mock_xqueue.send_to_queue.assert_called_with( body=json.dumps(contents), header=ANY) def update_score_single(self): self.openendedmodule.new_history_entry("New Entry") get = { 'queuekey': "abcd", 'xqueue_body': json.dumps(self.single_score_msg) } self.openendedmodule.update_score(get, self.test_system) def update_score_multiple(self): self.openendedmodule.new_history_entry("New Entry") get = { 'queuekey': "abcd", 'xqueue_body': json.dumps(self.multiple_score_msg) } self.openendedmodule.update_score(get, self.test_system) def test_latest_post_assessment(self): self.update_score_single() assessment = self.openendedmodule.latest_post_assessment( self.test_system) self.assertFalse(assessment == '') # check for errors self.assertFalse('errors' in assessment) def test_update_score_single(self): self.update_score_single() score = self.openendedmodule.latest_score() self.assertEqual(score, 4) def test_update_score_multiple(self): """ Tests that a score of [0, 1] gets aggregated to 1. A change in behavior added by @jbau """ self.update_score_multiple() score = self.openendedmodule.latest_score() self.assertEquals(score, 1) @patch('xmodule.open_ended_grading_classes.open_ended_module.log.error') def test_update_score_nohistory(self, error_logger): """ Tests error handling when there is no child_history """ # NOTE that we are not creating any history items get = { 'queuekey': "abcd", 'xqueue_body': json.dumps(self.multiple_score_msg) } error_msg = ( "Trying to update score without existing studentmodule child_history:\n" " location: i4x://edX/sa_test/selfassessment/SampleQuestion\n" " score: 1\n" " grader_ids: [u'1', u'2']\n" " submission_ids: [u'1', u'1']") self.openendedmodule.update_score(get, self.test_system) (msg, ), _ = error_logger.call_args self.assertTrue(error_logger.called) self.assertEqual(msg, error_msg) def test_open_ended_display(self): """ Test storing answer with the open ended module. """ # Create a module with no state yet. Important that this start off as a blank slate. test_module = OpenEndedModule(self.test_system, self.location, self.definition, self.descriptor, self.static_data, self.metadata) saved_response = "Saved response." submitted_response = "Submitted response." # Initially, there will be no stored answer. self.assertEqual(test_module.stored_answer, None) # And the initial answer to display will be an empty string. self.assertEqual(test_module.get_display_answer(), "") # Now, store an answer in the module. test_module.handle_ajax("store_answer", {'student_answer': saved_response}, get_test_system()) # The stored answer should now equal our response. self.assertEqual(test_module.stored_answer, saved_response) self.assertEqual(test_module.get_display_answer(), saved_response) # Mock out the send_to_grader function so it doesn't try to connect to the xqueue. test_module.send_to_grader = Mock(return_value=True) # Submit a student response to the question. test_module.handle_ajax("save_answer", {"student_answer": submitted_response}, get_test_system()) # Submitting an answer should clear the stored answer. self.assertEqual(test_module.stored_answer, None) # Confirm that the answer is stored properly. self.assertEqual(test_module.latest_answer(), submitted_response)
class OpenEndedModuleTest(unittest.TestCase): """ Test the open ended module class """ location = Location(["i4x", "edX", "sa_test", "selfassessment", "SampleQuestion"]) metadata = json.dumps({'attempts': '10'}) prompt = etree.XML("<prompt>This is a question prompt</prompt>") rubric = etree.XML('''<rubric> <category> <description>Response Quality</description> <option>The response is not a satisfactory answer to the question. It either fails to address the question or does so in a limited way, with no evidence of higher-order thinking.</option> </category> </rubric>''') max_score = 4 static_data = { 'max_attempts': 20, 'prompt': prompt, 'rubric': rubric, 'max_score': max_score, 'display_name': 'Name', 'accept_file_upload': False, 'close_date': None, 's3_interface': test_util_open_ended.S3_INTERFACE, 'open_ended_grading_interface': test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE, 'skip_basic_checks': False, } oeparam = etree.XML(''' <openendedparam> <initial_display>Enter essay here.</initial_display> <answer_display>This is the answer.</answer_display> <grader_payload>{"grader_settings" : "ml_grading.conf", "problem_id" : "6.002x/Welcome/OETest"}</grader_payload> </openendedparam> ''') definition = {'oeparam': oeparam} descriptor = Mock() def setUp(self): self.test_system = get_test_system() self.test_system.location = self.location self.mock_xqueue = MagicMock() self.mock_xqueue.send_to_queue.return_value = (None, "Message") def constructed_callback(dispatch="score_update"): return dispatch self.test_system.xqueue = {'interface': self.mock_xqueue, 'construct_callback': constructed_callback, 'default_queuename': 'testqueue', 'waittime': 1} self.openendedmodule = OpenEndedModule(self.test_system, self.location, self.definition, self.descriptor, self.static_data, self.metadata) def test_message_post(self): get = {'feedback': 'feedback text', 'submission_id': '1', 'grader_id': '1', 'score': 3} qtime = datetime.strftime(datetime.now(), xqueue_interface.dateformat) student_info = {'anonymous_student_id': self.test_system.anonymous_student_id, 'submission_time': qtime} contents = { 'feedback': get['feedback'], 'submission_id': int(get['submission_id']), 'grader_id': int(get['grader_id']), 'score': get['score'], 'student_info': json.dumps(student_info) } result = self.openendedmodule.message_post(get, self.test_system) self.assertTrue(result['success']) # make sure it's actually sending something we want to the queue self.mock_xqueue.send_to_queue.assert_called_with(body=json.dumps(contents), header=ANY) state = json.loads(self.openendedmodule.get_instance_state()) self.assertIsNotNone(state['child_state'], OpenEndedModule.DONE) def test_send_to_grader(self): submission = "This is a student submission" qtime = datetime.strftime(datetime.now(), xqueue_interface.dateformat) student_info = {'anonymous_student_id': self.test_system.anonymous_student_id, 'submission_time': qtime} contents = self.openendedmodule.payload.copy() contents.update({ 'student_info': json.dumps(student_info), 'student_response': submission, 'max_score': self.max_score }) result = self.openendedmodule.send_to_grader(submission, self.test_system) self.assertTrue(result) self.mock_xqueue.send_to_queue.assert_called_with(body=json.dumps(contents), header=ANY) def update_score_single(self): self.openendedmodule.new_history_entry("New Entry") score_msg = { 'correct': True, 'score': 4, 'msg': 'Grader Message', 'feedback': "Grader Feedback" } get = {'queuekey': "abcd", 'xqueue_body': score_msg} self.openendedmodule.update_score(get, self.test_system) def update_score_single(self): self.openendedmodule.new_history_entry("New Entry") feedback = { "success": True, "feedback": "Grader Feedback" } score_msg = { 'correct': True, 'score': 4, 'msg': 'Grader Message', 'feedback': json.dumps(feedback), 'grader_type': 'IN', 'grader_id': '1', 'submission_id': '1', 'success': True, 'rubric_scores': [0], 'rubric_scores_complete': True, 'rubric_xml': etree.tostring(self.rubric) } get = {'queuekey': "abcd", 'xqueue_body': json.dumps(score_msg)} self.openendedmodule.update_score(get, self.test_system) def test_latest_post_assessment(self): self.update_score_single() assessment = self.openendedmodule.latest_post_assessment(self.test_system) self.assertFalse(assessment == '') # check for errors self.assertFalse('errors' in assessment) def test_update_score(self): self.update_score_single() score = self.openendedmodule.latest_score() self.assertEqual(score, 4)
class OpenEndedModuleTest(unittest.TestCase): """ Test the open ended module class """ location = Location(["i4x", "edX", "sa_test", "selfassessment", "SampleQuestion"]) metadata = json.dumps({"attempts": "10"}) prompt = etree.XML("<prompt>This is a question prompt</prompt>") rubric = etree.XML( """<rubric> <category> <description>Response Quality</description> <option>The response is not a satisfactory answer to the question. It either fails to address the question or does so in a limited way, with no evidence of higher-order thinking.</option> </category> </rubric>""" ) max_score = 4 static_data = { "max_attempts": 20, "prompt": prompt, "rubric": rubric, "max_score": max_score, "display_name": "Name", "accept_file_upload": False, "close_date": None, "s3_interface": test_util_open_ended.S3_INTERFACE, "open_ended_grading_interface": test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE, "skip_basic_checks": False, "control": {"required_peer_grading": 1, "peer_grader_count": 1, "min_to_calibrate": 3, "max_to_calibrate": 6}, } oeparam = etree.XML( """ <openendedparam> <initial_display>Enter essay here.</initial_display> <answer_display>This is the answer.</answer_display> <grader_payload>{"grader_settings" : "ml_grading.conf", "problem_id" : "6.002x/Welcome/OETest"}</grader_payload> </openendedparam> """ ) definition = {"oeparam": oeparam} descriptor = Mock() def setUp(self): self.test_system = get_test_system() self.test_system.open_ended_grading_interface = None self.test_system.location = self.location self.mock_xqueue = MagicMock() self.mock_xqueue.send_to_queue.return_value = (None, "Message") def constructed_callback(dispatch="score_update"): return dispatch self.test_system.xqueue = { "interface": self.mock_xqueue, "construct_callback": constructed_callback, "default_queuename": "testqueue", "waittime": 1, } self.openendedmodule = OpenEndedModule( self.test_system, self.location, self.definition, self.descriptor, self.static_data, self.metadata ) def test_message_post(self): get = {"feedback": "feedback text", "submission_id": "1", "grader_id": "1", "score": 3} qtime = datetime.strftime(datetime.now(UTC), xqueue_interface.dateformat) student_info = {"anonymous_student_id": self.test_system.anonymous_student_id, "submission_time": qtime} contents = { "feedback": get["feedback"], "submission_id": int(get["submission_id"]), "grader_id": int(get["grader_id"]), "score": get["score"], "student_info": json.dumps(student_info), } result = self.openendedmodule.message_post(get, self.test_system) self.assertTrue(result["success"]) # make sure it's actually sending something we want to the queue self.mock_xqueue.send_to_queue.assert_called_with(body=json.dumps(contents), header=ANY) state = json.loads(self.openendedmodule.get_instance_state()) self.assertIsNotNone(state["child_state"], OpenEndedModule.DONE) def test_send_to_grader(self): submission = "This is a student submission" qtime = datetime.strftime(datetime.now(UTC), xqueue_interface.dateformat) student_info = {"anonymous_student_id": self.test_system.anonymous_student_id, "submission_time": qtime} contents = self.openendedmodule.payload.copy() contents.update( {"student_info": json.dumps(student_info), "student_response": submission, "max_score": self.max_score} ) result = self.openendedmodule.send_to_grader(submission, self.test_system) self.assertTrue(result) self.mock_xqueue.send_to_queue.assert_called_with(body=json.dumps(contents), header=ANY) def update_score_single(self): self.openendedmodule.new_history_entry("New Entry") score_msg = {"correct": True, "score": 4, "msg": "Grader Message", "feedback": "Grader Feedback"} get = {"queuekey": "abcd", "xqueue_body": score_msg} self.openendedmodule.update_score(get, self.test_system) def update_score_single(self): self.openendedmodule.new_history_entry("New Entry") feedback = {"success": True, "feedback": "Grader Feedback"} score_msg = { "correct": True, "score": 4, "msg": "Grader Message", "feedback": json.dumps(feedback), "grader_type": "IN", "grader_id": "1", "submission_id": "1", "success": True, "rubric_scores": [0], "rubric_scores_complete": True, "rubric_xml": etree.tostring(self.rubric), } get = {"queuekey": "abcd", "xqueue_body": json.dumps(score_msg)} self.openendedmodule.update_score(get, self.test_system) def update_score_multiple(self): self.openendedmodule.new_history_entry("New Entry") feedback = {"success": True, "feedback": "Grader Feedback"} score_msg = { "correct": True, "score": [0, 1], "msg": "Grader Message", "feedback": [json.dumps(feedback), json.dumps(feedback)], "grader_type": "PE", "grader_id": ["1", "2"], "submission_id": "1", "success": True, "rubric_scores": [[0], [0]], "rubric_scores_complete": [True, True], "rubric_xml": [etree.tostring(self.rubric), etree.tostring(self.rubric)], } get = {"queuekey": "abcd", "xqueue_body": json.dumps(score_msg)} self.openendedmodule.update_score(get, self.test_system) def test_latest_post_assessment(self): self.update_score_single() assessment = self.openendedmodule.latest_post_assessment(self.test_system) self.assertFalse(assessment == "") # check for errors self.assertFalse("errors" in assessment) def test_update_score_single(self): self.update_score_single() score = self.openendedmodule.latest_score() self.assertEqual(score, 4) def test_update_score_multiple(self): """ Tests that a score of [0, 1] gets aggregated to 1. A change in behavior added by @jbau """ self.update_score_multiple() score = self.openendedmodule.latest_score() self.assertEquals(score, 1)