def define_randomized_custom_response_problem(self, problem_url_name, redefine=False): """ Defines a custom response problem that uses a random value to determine correctness. Generated answer is also returned as the `msg`, so that the value can be used as a correct answer by a test. If the `redefine` flag is set, then change the definition of correctness (from equals to not-equals). """ factory = CustomResponseXMLFactory() script = textwrap.dedent( """ def check_func(expect, answer_given): expected = str(random.randint(0, 100)) return {'ok': answer_given %s expected, 'msg': expected} """ % ("!=" if redefine else "==") ) problem_xml = factory.build_xml(script=script, cfn="check_func", expect="42", num_responses=1) if redefine: self.module_store.update_item(InstructorTaskModuleTestCase.problem_location(problem_url_name), problem_xml) else: # Use "per-student" rerandomization so that check-problem can be called more than once. # Using "always" means we cannot check a problem twice, but we want to call once to get the # correct answer, and call a second time with that answer to confirm it's graded as correct. # Per-student rerandomization will at least generate different seeds for different users, so # we get a little more test coverage. ItemFactory.create( parent_location=self.problem_section.location, category="problem", display_name=str(problem_url_name), data=problem_xml, metadata={"rerandomize": "per_student"}, )
def singleton(cls): """ Return the singleton, creating one if it does not already exist.""" # If we haven't created the singleton yet, create it now if cls.SINGLETON is None: # Create a mock ModuleSystem, installing our cache system = mock.MagicMock(ModuleSystem) system.render_template = lambda template, context: "<div>%s</div>" % template system.cache = cache system.filestore = mock.MagicMock(fs.osfs.OSFS) system.filestore.root_path = "" system.DEBUG = True # Create a custom response problem xml_factory = CustomResponseXMLFactory() xml = xml_factory.build_xml(script=TEST_SCRIPT, cfn="check_func", expect="42") # Create and store the context cls.SINGLETON = cls(system, xml) else: pass # Return the singleton return cls.SINGLETON
def singleton(cls): """ Return the singleton, creating one if it does not already exist.""" # If we haven't created the singleton yet, create it now if cls.SINGLETON is None: # Create a mock ModuleSystem, installing our cache system = mock.MagicMock(ModuleSystem) system.STATIC_URL = '/dummy-static/' system.render_template = lambda template, context: "<div>%s</div>" % template system.cache = cache system.filestore = mock.MagicMock(fs.osfs.OSFS) system.filestore.root_path = "" system.DEBUG = True # Create a custom response problem xml_factory = CustomResponseXMLFactory() xml = xml_factory.build_xml(script=TEST_SCRIPT, cfn="check_func", expect="42") # Create and store the context cls.SINGLETON = cls(system, xml) else: pass # Return the singleton return cls.SINGLETON
def define_randomized_custom_response_problem(self, problem_url_name, redefine=False): """ Defines a custom response problem that uses a random value to determine correctness. Generated answer is also returned as the `msg`, so that the value can be used as a correct answer by a test. If the `redefine` flag is set, then change the definition of correctness (from equals to not-equals). """ factory = CustomResponseXMLFactory() script = textwrap.dedent(""" def check_func(expect, answer_given): expected = str(random.randint(0, 100)) return {'ok': answer_given %s expected, 'msg': expected} """ % ('!=' if redefine else '==')) problem_xml = factory.build_xml(script=script, cfn="check_func", expect="42", num_responses=1) if redefine: self.module_store.update_item(InstructorTaskModuleTestCase.problem_location(problem_url_name), problem_xml) else: # Use "per-student" rerandomization so that check-problem can be called more than once. # Using "always" means we cannot check a problem twice, but we want to call once to get the # correct answer, and call a second time with that answer to confirm it's graded as correct. # Per-student rerandomization will at least generate different seeds for different users, so # we get a little more test coverage. ItemFactory.create(parent_location=self.problem_section.location, template="i4x://edx/templates/problem/Blank_Common_Problem", display_name=str(problem_url_name), data=problem_xml, metadata={"rerandomize": "per_student"})
class ScriptProblemTypeTest(ProblemTypeTestBase, ProblemTypeTestMixin): """ TestCase Class for Script Problem Type """ problem_name = 'SCRIPT TEST PROBLEM' problem_type = 'script' partially_correct = False factory = CustomResponseXMLFactory() factory_kwargs = { 'cfn': 'test_add_to_ten', 'expect': '10', 'num_inputs': 2, 'question_text': 'Enter two integers that sum to 10.', 'input_element_label': 'Enter an integer', 'script': textwrap.dedent(""" def test_add_to_ten(expect,ans): try: a1=int(ans[0]) a2=int(ans[1]) except ValueError: a1=0 a2=0 return (a1+a2)==int(expect) """), } status_indicators = { 'correct': ['div.correct'], 'incorrect': ['div.incorrect'], 'unanswered': ['div.unanswered', 'div.unsubmitted'], } def setUp(self, *args, **kwargs): """ Additional setup for ScriptProblemTypeTest """ super(ScriptProblemTypeTest, self).setUp(*args, **kwargs) def answer_problem(self, correctness): """ Answer script problem. """ # Correct answer is any two integers that sum to 10 first_addend = random.randint(-100, 100) second_addend = 10 - first_addend # If we want an incorrect answer, then change # the second addend so they no longer sum to 10 if not correctness == 'correct': second_addend += random.randint(1, 10) self.problem_page.fill_answer(first_addend, input_num=0) self.problem_page.fill_answer(second_addend, input_num=1)
def computed_answer_setup(self, name): """ set up an example problem using an answer script''' """ script = self.COMPUTED_ANSWER_SCRIPT computed_xml = CustomResponseXMLFactory().build_xml(answer=script) ItemFactory.create(parent_location=self.section.location, category='problem', boilerplate='customgrader.yaml', data=computed_xml, display_name=name) # define the correct and incorrect responses to this problem self.correct_responses[name] = self.COMPUTED_ANSWER_CORRECT self.incorrect_responses[name] = self.COMPUTED_ANSWER_INCORRECT # re-fetch the course from the database so the object is up to date self.refresh_course()
def computed_answer_setup(self, name): """ set up an example problem using an answer script''' """ script = self.COMPUTED_ANSWER_SCRIPT custom_template = "i4x://edx/templates/problem/Custom_Python-Evaluated_Input" computed_xml = CustomResponseXMLFactory().build_xml(answer=script) ItemFactory.create(parent_location=self.section.location, template=custom_template, data=computed_xml, display_name=name) # define the correct and incorrect responses to this problem self.correct_responses[name] = self.COMPUTED_ANSWER_CORRECT self.incorrect_responses[name] = self.COMPUTED_ANSWER_INCORRECT # re-fetch the course from the database so the object is up to date self.refresh_course()
def custom_response_setup(self, name): """ set up an example custom response problem using a check function """ test_csv = self.CUSTOM_RESPONSE_SCRIPT expect = self.CUSTOM_RESPONSE_CORRECT cfn_problem_xml = CustomResponseXMLFactory().build_xml(script=test_csv, cfn='test_csv', expect=expect) ItemFactory.create( parent_location=self.section.location, category='problem', boilerplate='customgrader.yaml', data=cfn_problem_xml, display_name=name ) # define the correct and incorrect responses to this problem self.correct_responses[name] = expect self.incorrect_responses[name] = self.CUSTOM_RESPONSE_INCORRECT # re-fetch the course from the database so the object is up to date self.refresh_course()
def custom_response_setup(self, name): """ set up an example custom response problem using a check function """ custom_template = "i4x://edx/templates/problem/Custom_Python-Evaluated_Input" test_csv = self.CUSTOM_RESPONSE_SCRIPT expect = self.CUSTOM_RESPONSE_CORRECT cfn_problem_xml = CustomResponseXMLFactory().build_xml(script=test_csv, cfn='test_csv', expect=expect) ItemFactory.create(parent_location=self.section.location, template=custom_template, data=cfn_problem_xml, display_name=name) # define the correct and incorrect responses to this problem self.correct_responses[name] = expect self.incorrect_responses[name] = self.CUSTOM_RESPONSE_INCORRECT # re-fetch the course from the database so the object is up to date self.refresh_course()
'question_text': 'The solution is [mathjax]x^2+2x+y[/mathjax]', 'sample_dict': { 'x': (-100, 100), 'y': (-100, 100) }, 'num_samples': 10, 'tolerance': 0.00001, 'math_display': True, 'answer': 'x^2+2*x+y' }, 'correct': ['div.correct'], 'incorrect': ['div.incorrect'], 'unanswered': ['div.unanswered'] }, 'script': { 'factory': CustomResponseXMLFactory(), 'kwargs': { 'question_text': 'Enter two integers that sum to 10.', 'cfn': 'test_add_to_ten', 'expect': '10', 'num_inputs': 2, 'script': textwrap.dedent(""" def test_add_to_ten(expect,ans): try: a1=int(ans[0]) a2=int(ans[1])
class ScriptProblemTypeBase(ProblemTypeTestBase): """ ProblemTypeTestBase specialization for Script Problem Type """ problem_name = 'SCRIPT TEST PROBLEM' problem_type = 'script' problem_points = 2 partially_correct = False factory = CustomResponseXMLFactory() factory_kwargs = { 'cfn': 'test_add_to_ten', 'expect': '10', 'num_inputs': 2, 'question_text': 'Enter two integers that sum to 10.', 'input_element_label': 'Enter an integer', 'script': textwrap.dedent(""" def test_add_to_ten(expect,ans): try: a1=int(ans[0]) a2=int(ans[1]) except ValueError: a1=0 a2=0 return (a1+a2)==int(expect) """), } status_indicators = { 'correct': ['div.correct'], 'incorrect': ['div.incorrect'], 'unanswered': ['div.unanswered', 'div.unsubmitted'], 'submitted': ['div.submitted'], } def problem_status(self, status): """ Returns the status of problem Args: status(string): status of the problem which is to be checked Returns: True: If provided status is present on the page """ selector = ', '.join(self.status_indicators[status]) try: self.problem_page.wait_for_element_visibility(selector, 'Status is present', timeout=10) return True except BrokenPromise: return False def answer_problem(self, correctness): """ Answer script problem. """ # Correct answer is any two integers that sum to 10 first_addend = random.randint(-100, 100) second_addend = 10 - first_addend # If we want an incorrect answer, then change # the second addend so they no longer sum to 10 if not correctness == 'correct': second_addend += random.randint(1, 10) self.problem_page.fill_answer(first_addend, input_num=0) # lint-amnesty, pylint: disable=no-member self.problem_page.fill_answer(second_addend, input_num=1) # lint-amnesty, pylint: disable=no-member