def test_problem_submission(): runtime = WorkbenchRuntime() # WorkbenchRuntime has an id_generator, but most runtimes won't # (because the generator will be contextual), so we # pass it explicitly to parse_xml_string. problem_usage_id = runtime.parse_xml_string( """ <problem_demo> <textinput_demo name='vote_count' input_type='int'/> <script> numvotes = 4 </script> <equality_demo name='votes_named' left='./vote_count/@student_input' right='$numvotes'> Number of upvotes matches entered string </equality_demo> </problem_demo> """, runtime.id_generator) problem = runtime.get_block(problem_usage_id) json_data = json.dumps({"vote_count": [{"name": "input", "value": "4"}]}) resp = runtime.handle(problem, 'check', make_request(json_data)) resp_data = json.loads(text_of_response(resp).decode('utf-8')) assert resp_data['checkResults']['votes_named'] == True assert resp_data['checkResults']['votes_named'] == True
def test_correct_answer_submission(): runtime = WorkbenchRuntime() # WorkbenchRuntime has an id_generator, but most runtimes won't # (because the generator will be contextual), so we # pass it explicitly to parse_xml_string. brewing101_usage_id = runtime.parse_xml_string(""" <brewing101/> """, runtime.id_generator) brewing101 = runtime.get_block(brewing101_usage_id) json_data = json.dumps(172) resp = runtime.handle(brewing101, 'submit_answer', make_request(json_data)) resp_data = json.loads(text_of_response(resp)) print(resp_data) assert_equals(resp_data['answerCorrect'], True)
def test_problem_submission(): runtime = WorkbenchRuntime() problem_usage_id = runtime.parse_xml_string(""" <problem> <textinput name='vote_count' input_type='int'/> <script> numvotes = 4 </script> <equality name='votes_named' left='./vote_count/@student_input' right='$numvotes'> Number of upvotes matches entered string </equality> </problem> """) problem = runtime.get_block(problem_usage_id) json_data = json.dumps({"vote_count": [{"name": "input", "value": "4"}]}) resp = runtime.handle(problem, 'check', make_request(json_data)) resp_data = json.loads(text_of_response(resp)) assert_equals(resp_data['checkResults']['votes_named'], True)
def test_problem_submission(): runtime = WorkbenchRuntime() # WorkbenchRuntime has an id_generator, but most runtimes won't # (because the generator will be contextual), so we # pass it explicitly to parse_xml_string. problem_usage_id = runtime.parse_xml_string(""" <problem_demo> <textinput_demo name='vote_count' input_type='int'/> <script> numvotes = 4 </script> <equality_demo name='votes_named' left='./vote_count/@student_input' right='$numvotes'> Number of upvotes matches entered string </equality_demo> </problem_demo> """, runtime.id_generator) problem = runtime.get_block(problem_usage_id) json_data = json.dumps({"vote_count": [{"name": "input", "value": "4"}]}) resp = runtime.handle(problem, 'check', make_request(json_data)) resp_data = json.loads(text_of_response(resp)) assert_equals(resp_data['checkResults']['votes_named'], True)
class XBlockHandlerTestCaseMixin: """Load the XBlock in the workbench runtime to test its handler. """ def setUp(self): """Create the runtime. """ super(XBlockHandlerTestCaseMixin, self).setUp() self.runtime = WorkbenchRuntime() def set_user(self, user_id): """Provide a user ID to the runtime. Args: user_id (str): a user ID. Returns: None """ self.runtime.user_id = user_id def load_scenario(self, xml_path): """Load an XML definition of an XBlock and return the XBlock instance. Args: xml (string): Path to an XML definition of the XBlock, relative to the test module. Returns: XBlock """ block_id = self.runtime.parse_xml_string( self.load_fixture_str(xml_path), self.runtime.id_generator ) return self.runtime.get_block(block_id) def request(self, xblock, handler_name, content, request_method="POST", response_format=None): """Make a request to an XBlock handler. Args: xblock (XBlock): The XBlock instance that should handle the request. handler_name (str): The name of the handler. content (unicode): Content of the request. Keyword Arguments: request_method (str): The HTTP method of the request (defaults to POST) response_format (None or str): Expected format of the response string. If `None`, return the raw response content; if 'json', parse the response as JSON and return the result. Raises: NotImplementedError: Response format not supported. Returns: Content of the response (mixed). """ # Create a fake request request = webob.Request(dict()) request.method = request_method request.body = content # Send the request to the XBlock handler response = self.runtime.handle(xblock, handler_name, request) # Parse the response (if a format is specified) if response_format is None: return response.body elif response_format == 'json': return json.loads(response.body) else: raise NotImplementedError(u"Response format '{}' not supported".format(response_format)) @staticmethod def load_fixture_str(path): """Load data from a fixture file. Args: path (str): Path to the file. Returns: unicode: contents of the file. """ with open(path, 'rb') as file_handle: return file_handle.read()
class XBlockHandlerTestCaseMixin: """ Load the XBlock in the workbench runtime to test its handler. """ def setUp(self): """ Create the runtime. """ super().setUp() self.runtime = WorkbenchRuntime() mock_publish = mock.MagicMock(side_effect=self.runtime.publish) self.runtime.publish = mock_publish def set_user(self, user_id): """ Provide a user ID to the runtime. Args: user_id (str): a user ID. Returns: None """ self.runtime.user_id = user_id def load_scenario(self, xml_path): """ Load an XML definition of an XBlock and return the XBlock instance. Args: xml (string): Path to an XML definition of the XBlock, relative to the test module. Returns: XBlock """ block_id = self.runtime.parse_xml_string( self.load_fixture_str(xml_path), self.runtime.id_generator) return self.runtime.get_block(block_id) def request(self, xblock, handler_name, content, request_method="POST", response_format=None, use_runtime=True): """ Make a request to an XBlock handler. Args: xblock (XBlock): The XBlock instance that should handle the request. handler_name (str): The name of the handler. content (unicode): Content of the request. Keyword Arguments: request_method (str): The HTTP method of the request (defaults to POST) response_format (None or str): Expected format of the response string. If `None`, return the raw response content. If 'json', parse the response as JSON and return the result. If 'response', return the entire response object (helpful for asserting response codes). Raises: NotImplementedError: Response format not supported. Returns: Content of the response (mixed). """ # Create a fake request request = webob.Request({}) request.method = request_method request.body = content.encode('utf-8') # Send the request to the XBlock handler if use_runtime: response = self.runtime.handle(xblock, handler_name, request) else: response = getattr(xblock, handler_name)(request) # Parse the response (if a format is specified) if response_format is None: return response.body elif response_format == 'json': return json.loads(response.body.decode('utf-8')) elif response_format == 'response': return response else: raise NotImplementedError( f"Response format '{response_format}' not supported") def assert_assessment_event_published(self, xblock, event_name, assessment, **kwargs): """ Checks assessment event published successfuly. """ parts_list = [] for part in assessment["parts"]: # Some assessment parts do not include point values, # only written feedback. In this case, the assessment # part won't have an associated option. option_dict = None if part["option"] is not None: option_dict = { "name": part["option"]["name"], "points": part["option"]["points"], } # All assessment parts are associated with criteria criterion_dict = { "name": part["criterion"]["name"], "points_possible": part["criterion"]["points_possible"] } parts_list.append({ "option": option_dict, "criterion": criterion_dict, "feedback": part["feedback"] }) event_data = { "feedback": assessment["feedback"], "rubric": { "content_hash": assessment["rubric"]["content_hash"], }, "scorer_id": assessment["scorer_id"], "score_type": assessment["score_type"], "scored_at": assessment["scored_at"], "submission_uuid": assessment["submission_uuid"], "parts": parts_list } for key, value in kwargs.items(): event_data[key] = value self.assert_event_published(xblock, event_name, event_data) def assert_event_published(self, xblock, event_name, event_data): """ Assert that an event was emitted with the given parameters. Args: event_name(str): The name of the event emitted event_data(dict): A dictionary containing the data we expect to have publish """ self.runtime.publish.assert_any_call(xblock, event_name, event_data) @staticmethod def load_fixture_str(path): """ Load data from a fixture file. Args: path (str): Path to the file. Returns: unicode: contents of the file. """ base_dir = os.path.dirname(os.path.abspath(__file__)) with open(os.path.join(base_dir, path)) as file_handle: return file_handle.read()
class XBlockHandlerTestCaseMixin(object): """ Load the XBlock in the workbench runtime to test its handler. """ def setUp(self): """ Create the runtime. """ super(XBlockHandlerTestCaseMixin, self).setUp() self.runtime = WorkbenchRuntime() mock_publish = mock.MagicMock(side_effect=self.runtime.publish) self.runtime.publish = mock_publish def set_user(self, user_id): """ Provide a user ID to the runtime. Args: user_id (str): a user ID. Returns: None """ self.runtime.user_id = user_id def load_scenario(self, xml_path): """ Load an XML definition of an XBlock and return the XBlock instance. Args: xml (string): Path to an XML definition of the XBlock, relative to the test module. Returns: XBlock """ block_id = self.runtime.parse_xml_string( self.load_fixture_str(xml_path), self.runtime.id_generator ) return self.runtime.get_block(block_id) def request(self, xblock, handler_name, content, request_method="POST", response_format=None, use_runtime=True): """ Make a request to an XBlock handler. Args: xblock (XBlock): The XBlock instance that should handle the request. handler_name (str): The name of the handler. content (unicode): Content of the request. Keyword Arguments: request_method (str): The HTTP method of the request (defaults to POST) response_format (None or str): Expected format of the response string. If `None`, return the raw response content; if 'json', parse the response as JSON and return the result. Raises: NotImplementedError: Response format not supported. Returns: Content of the response (mixed). """ # Create a fake request request = webob.Request(dict()) request.method = request_method request.body = content # Send the request to the XBlock handler if use_runtime: response = self.runtime.handle(xblock, handler_name, request) else: response = getattr(xblock, handler_name)(request) # Parse the response (if a format is specified) if response_format is None: return response.body elif response_format == 'json': return json.loads(response.body) else: raise NotImplementedError("Response format '{format}' not supported".format(response_format)) def assert_assessment_event_published(self, xblock, event_name, assessment, **kwargs): parts_list = [] for part in assessment["parts"]: # Some assessment parts do not include point values, # only written feedback. In this case, the assessment # part won't have an associated option. option_dict = None if part["option"] is not None: option_dict = { "name": part["option"]["name"], "points": part["option"]["points"], } # All assessment parts are associated with criteria criterion_dict = { "name": part["criterion"]["name"], "points_possible": part["criterion"]["points_possible"] } parts_list.append({ "option": option_dict, "criterion": criterion_dict, "feedback": part["feedback"] }) event_data = { "feedback": assessment["feedback"], "rubric": { "content_hash": assessment["rubric"]["content_hash"], }, "scorer_id": assessment["scorer_id"], "score_type": assessment["score_type"], "scored_at": assessment["scored_at"], "submission_uuid": assessment["submission_uuid"], "parts": parts_list } for key in kwargs: event_data[key] = kwargs[key] self.assert_event_published( xblock, event_name, event_data ) def assert_event_published(self, xblock, event_name, event_data): """ Assert that an event was emitted with the given parameters. Args: event_name(str): The name of the event emitted event_data(dict): A dictionary containing the data we expect to have publish """ self.runtime.publish.assert_any_call( xblock, event_name, event_data ) @staticmethod def load_fixture_str(path): """ Load data from a fixture file. Args: path (str): Path to the file. Returns: unicode: contents of the file. """ base_dir = os.path.dirname(os.path.abspath(__file__)) with open(os.path.join(base_dir, path)) as file_handle: return file_handle.read()
class XBlockHandlerTestCaseMixin(object): """Load the XBlock in the workbench runtime to test its handler. """ def setUp(self): """Create the runtime. """ super(XBlockHandlerTestCaseMixin, self).setUp() self.runtime = WorkbenchRuntime() def set_user(self, user_id): """Provide a user ID to the runtime. Args: user_id (str): a user ID. Returns: None """ self.runtime.user_id = user_id def load_scenario(self, xml_path): """Load an XML definition of an XBlock and return the XBlock instance. Args: xml (string): Path to an XML definition of the XBlock, relative to the test module. Returns: XBlock """ block_id = self.runtime.parse_xml_string( self.load_fixture_str(xml_path), self.runtime.id_generator ) return self.runtime.get_block(block_id) def request(self, xblock, handler_name, content, request_method="POST", response_format=None): """Make a request to an XBlock handler. Args: xblock (XBlock): The XBlock instance that should handle the request. handler_name (str): The name of the handler. content (unicode): Content of the request. Keyword Arguments: request_method (str): The HTTP method of the request (defaults to POST) response_format (None or str): Expected format of the response string. If `None`, return the raw response content; if 'json', parse the response as JSON and return the result. Raises: NotImplementedError: Response format not supported. Returns: Content of the response (mixed). """ # Create a fake request request = webob.Request(dict()) request.method = request_method request.body = content # Send the request to the XBlock handler response = self.runtime.handle(xblock, handler_name, request) # Parse the response (if a format is specified) if response_format is None: return response.body elif response_format == 'json': return json.loads(response.body) else: raise NotImplementedError("Response format '{format}' not supported".format(response_format)) @staticmethod def load_fixture_str(path): """Load data from a fixture file. Args: path (str): Path to the file. Returns: unicode: contents of the file. """ with open(path, 'rb') as file_handle: return file_handle.read()