def setUpClass(cls): super(GradeTestBase, cls).setUpClass() cls.course = CourseFactory.create() cls.chapter = ItemFactory.create(parent=cls.course, category="chapter", display_name="Test Chapter") cls.sequence = ItemFactory.create(parent=cls.chapter, category='sequential', display_name="Test Sequential 1", graded=True, format="Homework") cls.vertical = ItemFactory.create(parent=cls.sequence, category='vertical', display_name='Test Vertical 1') problem_xml = MultipleChoiceResponseXMLFactory().build_xml( question_text='The correct answer is Choice 3', choices=[False, False, True, False], choice_names=['choice_0', 'choice_1', 'choice_2', 'choice_3']) cls.problem = ItemFactory.create(parent=cls.vertical, category="problem", display_name="Test Problem", data=problem_xml)
def users_and_problem_setup(self): self.chapter = ItemFactory.create(parent=self.course, category="chapter", display_name="Test Chapter") self.sequence = ItemFactory.create(parent=self.chapter, category='sequential', display_name="Test Sequential 1", graded=True, format="Homework") self.vertical = ItemFactory.create(parent=self.sequence, category='vertical', display_name='Test Vertical 1') problem_xml = MultipleChoiceResponseXMLFactory().build_xml( question_text='The correct answer is Choice 3', choices=[False, False, True, False], choice_names=['choice_0', 'choice_1', 'choice_2', 'choice_3']) self.problem = ItemFactory.create(parent=self.vertical, category="problem", display_name="Test Problem", data=problem_xml) self.user2 = UserFactory.create(username='******', password='******') self.user3 = UserFactory.create(username='******', password='******') self.request = get_mock_request(self.user)
def create_course_data(cls): # pylint: disable=missing-docstring cls.invalid_course_id = 'foo/bar/baz' cls.course = CourseFactory.create( display_name='An Introduction to API Testing', raw_grader=cls.raw_grader) cls.course_id = unicode(cls.course.id) with cls.store.bulk_operations(cls.course.id, emit_signals=False): cls.sequential = ItemFactory.create( category="sequential", parent_location=cls.course.location, display_name="Lesson 1", format="Homework", graded=True) factory = MultipleChoiceResponseXMLFactory() args = {'choices': [False, True, False]} problem_xml = factory.build_xml(**args) cls.problem = ItemFactory.create( category="problem", parent_location=cls.sequential.location, display_name="Problem 1", format="Homework", data=problem_xml, ) cls.video = ItemFactory.create( category="video", parent_location=cls.sequential.location, display_name="Video 1", ) cls.html = ItemFactory.create( category="html", parent_location=cls.sequential.location, display_name="HTML 1", )
def setUpClass(cls): super(TestStudentModuleGrading, cls).setUpClass() cls.course = CourseFactory.create() cls.chapter = ItemFactory.create(parent=cls.course, category="chapter", display_name="Test Chapter") cls.sequence = ItemFactory.create(parent=cls.chapter, category='sequential', display_name="Test Sequential 1", graded=True) cls.vertical = ItemFactory.create(parent=cls.sequence, category='vertical', display_name='Test Vertical 1') problem_xml = MultipleChoiceResponseXMLFactory().build_xml( question_text='The correct answer is Choice 3', choices=[False, False, True, False], choice_names=['choice_0', 'choice_1', 'choice_2', 'choice_3']) cls.problem = ItemFactory.create(parent=cls.vertical, category="problem", display_name="Test Problem", data=problem_xml) cls.request = get_mock_request(UserFactory()) cls.user = cls.request.user cls.instructor = UserFactory(username='******', is_staff=True)
class MultipleChoiceProblemTypeTest(ProblemTypeTestBase, ProblemTypeTestMixin): """ TestCase Class for Multiple Choice Problem Type """ problem_name = 'MULTIPLE CHOICE TEST PROBLEM' problem_type = 'multiple choice' factory = MultipleChoiceResponseXMLFactory() partially_correct = False factory_kwargs = { 'question_text': 'The correct answer is Choice 2', 'choices': [False, False, True, False], 'choice_names': ['choice_0', 'choice_1', 'choice_2', 'choice_3'], } status_indicators = { 'correct': ['label.choicegroup_correct'], 'incorrect': ['label.choicegroup_incorrect', 'span.incorrect'], 'unanswered': ['span.unanswered'], } def setUp(self, *args, **kwargs): """ Additional setup for MultipleChoiceProblemTypeTest """ super(MultipleChoiceProblemTypeTest, self).setUp(*args, **kwargs) def answer_problem(self, correctness): """ Answer multiple choice problem. """ if correctness == 'incorrect': self.problem_page.click_choice("choice_choice_1") else: self.problem_page.click_choice("choice_choice_2")
def setUpClass(cls): super(GradesEventIntegrationTest, cls).setUpClass() with cls.store.default_store(ModuleStoreEnum.Type.split): cls.course = CourseFactory.create() cls.chapter = ItemFactory.create(parent=cls.course, category="chapter", display_name="Test Chapter") cls.sequence = ItemFactory.create(parent=cls.chapter, category='sequential', display_name="Test Sequential 1", graded=True, format="Homework") cls.vertical = ItemFactory.create(parent=cls.sequence, category='vertical', display_name='Test Vertical 1') problem_xml = MultipleChoiceResponseXMLFactory().build_xml( question_text='The correct answer is Choice 2', choices=[False, False, True, False], choice_names=['choice_0', 'choice_1', 'choice_2', 'choice_3']) cls.problem = ItemFactory.create(parent=cls.vertical, category="problem", display_name="p1", data=problem_xml, metadata={'weight': 2})
def setUp(self): """ Test case scaffolding """ super().setUp() self.course = CourseFactory.create( metadata={ 'entrance_exam_enabled': True, } ) with self.store.bulk_operations(self.course.id): self.chapter = ItemFactory.create( parent=self.course, display_name='Overview' ) self.welcome = ItemFactory.create( parent=self.chapter, display_name='Welcome' ) ItemFactory.create( parent=self.course, category='chapter', display_name="Week 1" ) self.chapter_subsection = ItemFactory.create( parent=self.chapter, category='sequential', display_name="Lesson 1" ) chapter_vertical = ItemFactory.create( parent=self.chapter_subsection, category='vertical', display_name='Lesson 1 Vertical - Unit 1' ) ItemFactory.create( parent=chapter_vertical, category="problem", display_name="Problem - Unit 1 Problem 1" ) ItemFactory.create( parent=chapter_vertical, category="problem", display_name="Problem - Unit 1 Problem 2" ) ItemFactory.create( category="instructor", parent=self.course, data="Instructor Tab", display_name="Instructor" ) self.entrance_exam = ItemFactory.create( parent=self.course, category="chapter", display_name="Entrance Exam Section - Chapter 1", is_entrance_exam=True, in_entrance_exam=True ) self.exam_1 = ItemFactory.create( parent=self.entrance_exam, category='sequential', display_name="Exam Sequential - Subsection 1", graded=True, in_entrance_exam=True ) subsection = ItemFactory.create( parent=self.exam_1, category='vertical', display_name='Exam Vertical - Unit 1' ) problem_xml = MultipleChoiceResponseXMLFactory().build_xml( question_text='The correct answer is Choice 3', choices=[False, False, True, False], choice_names=['choice_0', 'choice_1', 'choice_2', 'choice_3'] ) self.problem_1 = ItemFactory.create( parent=subsection, category="problem", display_name="Exam Problem - Problem 1", data=problem_xml ) self.problem_2 = ItemFactory.create( parent=subsection, category="problem", display_name="Exam Problem - Problem 2" ) add_entrance_exam_milestone(self.course, self.entrance_exam) self.course.entrance_exam_enabled = True self.course.entrance_exam_minimum_score_pct = 0.50 self.course.entrance_exam_id = str(self.entrance_exam.scope_ids.usage_id) self.anonymous_user = AnonymousUserFactory() self.addCleanup(set_current_request, None) self.request = get_mock_request(UserFactory()) modulestore().update_item(self.course, self.request.user.id) self.client.login(username=self.request.user.username, password="******") CourseEnrollment.enroll(self.request.user, self.course.id) self.expected_locked_toc = ( [ { 'active': True, 'sections': [ { 'url_name': 'Exam_Sequential_-_Subsection_1', 'display_name': 'Exam Sequential - Subsection 1', 'graded': True, 'format': '', 'due': None, 'active': True } ], 'url_name': 'Entrance_Exam_Section_-_Chapter_1', 'display_name': 'Entrance Exam Section - Chapter 1', 'display_id': 'entrance-exam-section-chapter-1', } ] ) self.expected_unlocked_toc = ( [ { 'active': False, 'sections': [ { 'url_name': 'Welcome', 'display_name': 'Welcome', 'graded': False, 'format': '', 'due': None, 'active': False }, { 'url_name': 'Lesson_1', 'display_name': 'Lesson 1', 'graded': False, 'format': '', 'due': None, 'active': False } ], 'url_name': 'Overview', 'display_name': 'Overview', 'display_id': 'overview' }, { 'active': False, 'sections': [], 'url_name': 'Week_1', 'display_name': 'Week 1', 'display_id': 'week-1' }, { 'active': False, 'sections': [], 'url_name': 'Instructor', 'display_name': 'Instructor', 'display_id': 'instructor' }, { 'active': True, 'sections': [ { 'url_name': 'Exam_Sequential_-_Subsection_1', 'display_name': 'Exam Sequential - Subsection 1', 'graded': True, 'format': '', 'due': None, 'active': True } ], 'url_name': 'Entrance_Exam_Section_-_Chapter_1', 'display_name': 'Entrance Exam Section - Chapter 1', 'display_id': 'entrance-exam-section-chapter-1' } ] )
def setUpClass(cls): super(TestGetModuleScore, cls).setUpClass() cls.course = CourseFactory.create() cls.chapter = ItemFactory.create(parent=cls.course, category="chapter", display_name="Test Chapter") cls.seq1 = ItemFactory.create(parent=cls.chapter, category='sequential', display_name="Test Sequential 1", graded=True) cls.seq2 = ItemFactory.create(parent=cls.chapter, category='sequential', display_name="Test Sequential 2", graded=True) cls.seq3 = ItemFactory.create(parent=cls.chapter, category='sequential', display_name="Test Sequential 3", graded=True) cls.vert1 = ItemFactory.create(parent=cls.seq1, category='vertical', display_name='Test Vertical 1') cls.vert2 = ItemFactory.create(parent=cls.seq2, category='vertical', display_name='Test Vertical 2') cls.vert3 = ItemFactory.create(parent=cls.seq3, category='vertical', display_name='Test Vertical 3') cls.randomize = ItemFactory.create(parent=cls.vert2, category='randomize', display_name='Test Randomize') cls.library_content = ItemFactory.create( parent=cls.vert3, category='library_content', display_name='Test Library Content') problem_xml = MultipleChoiceResponseXMLFactory().build_xml( question_text='The correct answer is Choice 3', choices=[False, False, True, False], choice_names=['choice_0', 'choice_1', 'choice_2', 'choice_3']) cls.problem1 = ItemFactory.create(parent=cls.vert1, category="problem", display_name="Test Problem 1", data=problem_xml) cls.problem2 = ItemFactory.create(parent=cls.vert1, category="problem", display_name="Test Problem 2", data=problem_xml) cls.problem3 = ItemFactory.create(parent=cls.randomize, category="problem", display_name="Test Problem 3", data=problem_xml) cls.problem4 = ItemFactory.create(parent=cls.randomize, category="problem", display_name="Test Problem 4", data=problem_xml) cls.problem5 = ItemFactory.create(parent=cls.library_content, category="problem", display_name="Test Problem 5", data=problem_xml) cls.problem6 = ItemFactory.create(parent=cls.library_content, category="problem", display_name="Test Problem 6", data=problem_xml)
class MultipleChoiceProblemTypeTest(ProblemTypeTestBase, ProblemTypeTestMixin): """ TestCase Class for Multiple Choice Problem Type """ problem_name = 'MULTIPLE CHOICE TEST PROBLEM' problem_type = 'multiple choice' factory = MultipleChoiceResponseXMLFactory() partially_correct = False factory_kwargs = { 'question_text': 'The correct answer is Choice 2', 'choices': [False, False, True, False], 'choice_names': ['choice_0', 'choice_1', 'choice_2', 'choice_3'], } status_indicators = { 'correct': ['label.choicegroup_correct'], 'incorrect': ['label.choicegroup_incorrect', 'span.incorrect'], 'unanswered': ['span.unanswered'], } def setUp(self, *args, **kwargs): """ Additional setup for MultipleChoiceProblemTypeTest """ super(MultipleChoiceProblemTypeTest, self).setUp(*args, **kwargs) def answer_problem(self, correctness): """ Answer multiple choice problem. """ if correctness == 'incorrect': self.problem_page.click_choice("choice_choice_1") else: self.problem_page.click_choice("choice_choice_2") @attr(shard=7) def test_can_show_answer(self): """ Scenario: Verifies that show answer button is working as expected. Given that I am on courseware page And I can see a CAPA problem with show answer button When I click "Show Answer" button The correct answer is displayed with a single correctness indicator. """ # Click the correct answer, but don't submit yet. No correctness shows. self.answer_problem('correct') self.assertFalse(self.problem_page.is_correct_choice_highlighted(correct_choices=[3])) # After submit, the answer should be marked as correct. self.problem_page.click_submit() self.assertTrue(self.problem_page.is_correct_choice_highlighted(correct_choices=[3])) # Switch to an incorrect answer. This will hide the correctness indicator. self.answer_problem('incorrect') self.assertFalse(self.problem_page.is_correct_choice_highlighted(correct_choices=[3])) # Now click Show Answer. A single correctness indicator should be shown. self.problem_page.click_show() self.assertTrue(self.problem_page.is_correct_choice_highlighted(correct_choices=[3])) # Finally, make sure that clicking Show Answer moved focus to the correct place. self.problem_page.wait_for_show_answer_notification()
def setUp(self): super(TestCourseGradeLogging, self).setUp() self.course = CourseFactory.create() with self.store.bulk_operations(self.course.id): self.chapter = ItemFactory.create( parent=self.course, category="chapter", display_name="Test Chapter" ) self.sequence = ItemFactory.create( parent=self.chapter, category='sequential', display_name="Test Sequential 1", graded=True ) self.sequence_2 = ItemFactory.create( parent=self.chapter, category='sequential', display_name="Test Sequential 2", graded=True ) self.sequence_3 = ItemFactory.create( parent=self.chapter, category='sequential', display_name="Test Sequential 3", graded=False ) self.vertical = ItemFactory.create( parent=self.sequence, category='vertical', display_name='Test Vertical 1' ) self.vertical_2 = ItemFactory.create( parent=self.sequence_2, category='vertical', display_name='Test Vertical 2' ) self.vertical_3 = ItemFactory.create( parent=self.sequence_3, category='vertical', display_name='Test Vertical 3' ) problem_xml = MultipleChoiceResponseXMLFactory().build_xml( question_text='The correct answer is Choice 2', choices=[False, False, True, False], choice_names=['choice_0', 'choice_1', 'choice_2', 'choice_3'] ) self.problem = ItemFactory.create( parent=self.vertical, category="problem", display_name="test_problem_1", data=problem_xml ) self.problem_2 = ItemFactory.create( parent=self.vertical_2, category="problem", display_name="test_problem_2", data=problem_xml ) self.problem_3 = ItemFactory.create( parent=self.vertical_3, category="problem", display_name="test_problem_3", data=problem_xml ) self.request = get_mock_request(UserFactory()) self.client.login(username=self.request.user.username, password="******") self.course_structure = get_course_blocks(self.request.user, self.course.location) self.subsection_grade_factory = SubsectionGradeFactory(self.request.user, self.course, self.course_structure) CourseEnrollment.enroll(self.request.user, self.course.id)
def test_rescoring_events(self, models_tracker, handlers_tracker, instructor_task_tracker): # submit answer self.submit_question_answer('p1', {'2_1': 'choice_choice_3'}) models_tracker.reset_mock() handlers_tracker.reset_mock() new_problem_xml = MultipleChoiceResponseXMLFactory().build_xml( question_text='The correct answer is Choice 3', choices=[False, False, False, True], choice_names=['choice_0', 'choice_1', 'choice_2', 'choice_3']) module_store = modulestore() with module_store.branch_setting( ModuleStoreEnum.Branch.draft_preferred, self.course.id): self.problem.data = new_problem_xml module_store.update_item(self.problem, self.instructor.id) module_store.publish(self.problem.location, self.instructor.id) submit_rescore_problem_for_student(request=get_mock_request( self.instructor), usage_key=self.problem.location, student=self.student, only_if_higher=False) # check logging to make sure id's are tracked correctly across # events event_transaction_id = instructor_task_tracker.emit.mock_calls[0][1][ 1]['event_transaction_id'] self.assertEqual( instructor_task_tracker.get_tracker().context.call_args[0], ('edx.grades.problem.rescored', { 'course_id': unicode(self.course.id), 'org_id': unicode(self.course.org) })) # make sure the id is propagated throughout the event flow for call in models_tracker.emit.mock_calls: self.assertEqual(event_transaction_id, call[1][1]['event_transaction_id']) self.assertEqual(unicode(RESCORE_TYPE), call[1][1]['event_transaction_type']) # make sure the models calls have re-added the course id to the context for args in models_tracker.get_tracker().context.call_args_list: self.assertEqual( args[0][1], { 'course_id': unicode(self.course.id), 'org_id': unicode(self.course.org) }) handlers_tracker.assert_not_called() instructor_task_tracker.emit.assert_called_with( unicode(RESCORE_TYPE), { 'course_id': unicode(self.course.id), 'user_id': unicode(self.student.id), 'problem_id': unicode(self.problem.location), 'new_weighted_earned': 2, 'new_weighted_possible': 2, 'only_if_higher': False, 'instructor_id': unicode(self.instructor.id), 'event_transaction_id': event_transaction_id, 'event_transaction_type': unicode(RESCORE_TYPE), }) course = modulestore().get_course(self.course.id, depth=0) models_tracker.emit.assert_called_with( u'edx.grades.course.grade_calculated', { 'course_version': unicode(course.course_version), 'percent_grade': 0.02, 'grading_policy_hash': u'ChVp0lHGQGCevD0t4njna/C44zQ=', 'user_id': unicode(self.student.id), 'letter_grade': u'', 'event_transaction_id': event_transaction_id, 'event_transaction_type': unicode(RESCORE_TYPE), 'course_id': unicode(self.course.id), 'course_edited_timestamp': unicode(course.subtree_edited_on), }) instructor_task_tracker.reset_mock() models_tracker.reset_mock() handlers_tracker.reset_mock()
# 'correct', 'incorrect', and 'unanswered' keys are lists of CSS selectors # the presence of any in the list is sufficient PROBLEM_DICT = { 'drop down': { 'factory': OptionResponseXMLFactory(), 'kwargs': { 'question_text': 'The correct answer is Option 2', 'options': ['Option 1', 'Option 2', 'Option 3', 'Option 4'], 'correct_option': 'Option 2' }, 'correct': ['span.correct'], 'incorrect': ['span.incorrect'], 'unanswered': ['span.unanswered'] }, 'multiple choice': { 'factory': MultipleChoiceResponseXMLFactory(), 'kwargs': { 'question_text': 'The correct answer is Choice 3', 'choices': [False, False, True, False], 'choice_names': ['choice_0', 'choice_1', 'choice_2', 'choice_3'] }, 'correct': ['label.choicegroup_correct', 'span.correct'], 'incorrect': ['label.choicegroup_incorrect', 'span.incorrect'], 'unanswered': ['span.unanswered'] }, 'checkbox': { 'factory': ChoiceResponseXMLFactory(), 'kwargs': { 'question_text': 'The correct answer is Choices 1 and 3', 'choice_type': 'checkbox', 'choices': [True, False, True, False, False],
def test_rescoring_events(self): self.submit_question_answer('p1', {'2_1': 'choice_choice_3'}) new_problem_xml = MultipleChoiceResponseXMLFactory().build_xml( question_text='The correct answer is Choice 3', choices=[False, False, False, True], choice_names=['choice_0', 'choice_1', 'choice_2', 'choice_3']) with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id): self.problem.data = new_problem_xml self.store.update_item(self.problem, self.instructor.id) self.store.publish(self.problem.location, self.instructor.id) with patch('lms.djangoapps.grades.events.tracker') as events_tracker: submit_rescore_problem_for_student(request=get_mock_request( self.instructor), usage_key=self.problem.location, student=self.student, only_if_higher=False) course = self.store.get_course(self.course.id, depth=0) # make sure the tracker's context is updated with course info for args in events_tracker.get_tracker().context.call_args_list: self.assertEqual( args[0][1], { 'course_id': six.text_type(self.course.id), 'org_id': six.text_type(self.course.org) }) event_transaction_id = events_tracker.emit.mock_calls[0][1][1][ 'event_transaction_id'] events_tracker.emit.assert_has_calls( [ mock_call( events.GRADES_RESCORE_EVENT_TYPE, { 'course_id': six.text_type(self.course.id), 'user_id': six.text_type(self.student.id), 'problem_id': six.text_type(self.problem.location), 'new_weighted_earned': 2, 'new_weighted_possible': 2, 'only_if_higher': False, 'instructor_id': six.text_type(self.instructor.id), 'event_transaction_id': event_transaction_id, 'event_transaction_type': events.GRADES_RESCORE_EVENT_TYPE, }, ), mock_call( events.COURSE_GRADE_CALCULATED, { 'course_version': six.text_type(course.course_version), 'percent_grade': 0.02, 'grading_policy_hash': u'ChVp0lHGQGCevD0t4njna/C44zQ=', 'user_id': six.text_type(self.student.id), 'letter_grade': u'', 'event_transaction_id': event_transaction_id, 'event_transaction_type': events.GRADES_RESCORE_EVENT_TYPE, 'course_id': six.text_type(self.course.id), 'course_edited_timestamp': six.text_type(course.subtree_edited_on), }, ), ], any_order=True, )