From c09632ef69071cd06d2a085ec20ac9532206e7d9 Mon Sep 17 00:00:00 2001 From: cahrens Date: Mon, 20 Oct 2014 17:16:40 -0400 Subject: [PATCH] Tests for conditional content (split_test module). TNL-39 --- .../tests/test_submitting_problems.py | 224 +++++++++++++++++- 1 file changed, 215 insertions(+), 9 deletions(-) diff --git a/lms/djangoapps/courseware/tests/test_submitting_problems.py b/lms/djangoapps/courseware/tests/test_submitting_problems.py index f3d4cc9e2b..0c864938fb 100644 --- a/lms/djangoapps/courseware/tests/test_submitting_problems.py +++ b/lms/djangoapps/courseware/tests/test_submitting_problems.py @@ -32,11 +32,14 @@ from lms.lib.xblock.runtime import quote_slashes from student.tests.factories import UserFactory from student.models import anonymous_id_for_user +from xmodule.partitions.partitions import Group, UserPartition +from user_api.tests.factories import UserCourseTagFactory + @override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestSubmittingProblems(ModuleStoreTestCase, LoginEnrollmentTestCase): """ - Check that a course gets graded properly. + Check that a course gets graded properly. """ # arbitrary constant @@ -217,12 +220,6 @@ class TestSubmittingProblems(ModuleStoreTestCase, LoginEnrollmentTestCase): self.refresh_course() return section - -class TestCourseGrader(TestSubmittingProblems): - """ - Suite of tests for the course grader. - """ - def add_grading_policy(self, grading_policy): """ Add a grading policy to the course. @@ -283,7 +280,7 @@ class TestCourseGrader(TestSubmittingProblems): """ Global scores, each Score is a Problem Set. - Returns list of scores: [, , ..., ] + Returns list of scores: [, , ..., ] """ return [s.earned for s in self.get_grade_summary()['totaled_scores']['Homework']] @@ -292,7 +289,7 @@ class TestCourseGrader(TestSubmittingProblems): Returns list of scores for a given url. Returns list of scores for the given homework: - [, , ..., ] + [, , ..., ] """ # list of grade summaries for each section @@ -304,6 +301,11 @@ class TestCourseGrader(TestSubmittingProblems): hw_section = next(section for section in sections_list if section.get('url_name') == hw_url_name) return [s.earned for s in hw_section['scores']] + +class TestCourseGrader(TestSubmittingProblems): + """ + Suite of tests for the course grader. + """ def basic_setup(self, late=False, reset=False, showanswer=False): """ Set up a simple course for testing basic grading functionality. @@ -1050,3 +1052,207 @@ class TestAnswerDistributions(TestSubmittingProblems): }, } ) + + +class TestConditionalContent(TestSubmittingProblems): + """ + Check that conditional content works correctly with grading. + """ + def setUp(self): + """ + Set up a simple course with a grading policy, a UserPartition, and 2 sections, both graded as "homework". + One section is pre-populated with a problem (with 2 inputs), visible to all students. + The second section is empty. Test cases should add conditional content to it. + """ + super(TestConditionalContent, self).setUp() + + self.user_partition_group_0 = 0 + self.user_partition_group_1 = 1 + self.partition = UserPartition( + 0, + 'first_partition', + 'First Partition', + [ + Group(self.user_partition_group_0, 'alpha'), + Group(self.user_partition_group_1, 'beta') + ] + ) + + self.course = CourseFactory.create( + display_name=self.COURSE_NAME, + number=self.COURSE_SLUG, + user_partitions=[self.partition] + ) + + grading_policy = { + "GRADER": [{ + "type": "Homework", + "min_count": 2, + "drop_count": 0, + "short_label": "HW", + "weight": 1.0 + }] + } + self.add_grading_policy(grading_policy) + + self.homework_all = self.add_graded_section_to_course('homework1') + self.p1_all_html_id = self.add_dropdown_to_section(self.homework_all.location, 'H1P1', 2).location.html_id() + + self.homework_conditional = self.add_graded_section_to_course('homework2') + + def split_setup(self, user_partition_group): + """ + Setup for tests using split_test module. Creates a split_test instance as a child of self.homework_conditional + with 2 verticals in it, and assigns self.student_user to the specified user_partition_group. + + The verticals are returned. + """ + vertical_0_url = self.course.id.make_usage_key("vertical", "split_test_vertical_0") + vertical_1_url = self.course.id.make_usage_key("vertical", "split_test_vertical_1") + + group_id_to_child = {} + for index, url in enumerate([vertical_0_url, vertical_1_url]): + group_id_to_child[str(index)] = url + + split_test = ItemFactory.create( + parent_location=self.homework_conditional.location, + category="split_test", + display_name="Split test", + user_partition_id='0', + group_id_to_child=group_id_to_child, + ) + + vertical_0 = ItemFactory.create( + parent_location=split_test.location, + category="vertical", + display_name="Condition 0 vertical", + location=vertical_0_url, + ) + + vertical_1 = ItemFactory.create( + parent_location=split_test.location, + category="vertical", + display_name="Condition 1 vertical", + location=vertical_1_url, + ) + + # Now add the student to the specified group. + UserCourseTagFactory( + user=self.student_user, + course_id=self.course.id, + key='xblock.partition_service.partition_{0}'.format(self.partition.id), # pylint: disable=no-member + value=str(user_partition_group) + ) + + return vertical_0, vertical_1 + + def split_different_problems_setup(self, user_partition_group): + """ + Setup for the case where the split test instance contains problems for each group + (so both groups do have graded content, though it is different). + + Group 0 has 2 problems, worth 1 and 3 points respectively. + Group 1 has 1 problem, worth 1 point. + + This method also assigns self.student_user to the specified user_partition_group and + then submits answers for the problems in section 1, which are visible to all students. + The submitted answers give the student 1 point out of a possible 2 points in the section. + """ + vertical_0, vertical_1 = self.split_setup(user_partition_group) + + # Group 0 will have 2 problems in the section, worth a total of 4 points. + self.add_dropdown_to_section(vertical_0.location, 'H2P1', 1).location.html_id() + self.add_dropdown_to_section(vertical_0.location, 'H2P2', 3).location.html_id() + + # Group 1 will have 1 problem in the section, worth a total of 1 point. + self.add_dropdown_to_section(vertical_1.location, 'H2P1', 1).location.html_id() + + # Submit answers for problem in Section 1, which is visible to all students. + self.submit_question_answer('H1P1', {'2_1': 'Correct', '2_2': 'Incorrect'}) + + def test_split_different_problems_group_0(self): + """ + Tests that users who see different problems in a split_test module instance are graded correctly. + This is the test case for a user in user partition group 0. + """ + self.split_different_problems_setup(self.user_partition_group_0) + + self.submit_question_answer('H2P1', {'2_1': 'Correct'}) + self.submit_question_answer('H2P2', {'2_1': 'Correct', '2_2': 'Incorrect', '2_3': 'Correct'}) + + self.assertEqual(self.score_for_hw('homework1'), [1.0]) + self.assertEqual(self.score_for_hw('homework2'), [1.0, 2.0]) + self.assertEqual(self.earned_hw_scores(), [1.0, 3.0]) + + # Grade percent is .63. Here is the calculation + homework_1_score = 1.0 / 2 + homework_2_score = (1.0 + 2.0) / 4 + self.check_grade_percent(round((homework_1_score + homework_2_score) / 2, 2)) + + def test_split_different_problems_group_1(self): + """ + Tests that users who see different problems in a split_test module instance are graded correctly. + This is the test case for a user in user partition group 1. + """ + self.split_different_problems_setup(self.user_partition_group_1) + + self.submit_question_answer('H2P1', {'2_1': 'Correct'}) + + self.assertEqual(self.score_for_hw('homework1'), [1.0]) + self.assertEqual(self.score_for_hw('homework2'), [1.0]) + self.assertEqual(self.earned_hw_scores(), [1.0, 1.0]) + + # Grade percent is .75. Here is the calculation + homework_1_score = 1.0 / 2 + homework_2_score = 1.0 / 1 + self.check_grade_percent(round((homework_1_score + homework_2_score) / 2, 2)) + + def split_one_group_no_problems_setup(self, user_partition_group): + """ + Setup for the case where the split test instance contains problems on for one group. + + Group 0 has no problems. + Group 1 has 1 problem, worth 1 point. + + This method also assigns self.student_user to the specified user_partition_group and + then submits answers for the problems in section 1, which are visible to all students. + The submitted answers give the student 2 points out of a possible 2 points in the section. + """ + [_, vertical_1] = self.split_setup(user_partition_group) + + # Group 1 will have 1 problem in the section, worth a total of 1 point. + self.add_dropdown_to_section(vertical_1.location, 'H2P1', 1).location.html_id() + + self.submit_question_answer('H1P1', {'2_1': 'Correct'}) + + def test_split_one_group_no_problems_group_0(self): + """ + Tests what happens when a given group has no problems in it (students receive 0 for that section). + """ + self.split_one_group_no_problems_setup(self.user_partition_group_0) + + self.assertEqual(self.score_for_hw('homework1'), [1.0]) + self.assertEqual(self.score_for_hw('homework2'), []) + self.assertEqual(self.earned_hw_scores(), [1.0, 0.0]) + + # Grade percent is .25. Here is the calculation. + homework_1_score = 1.0 / 2 + homework_2_score = 0.0 + self.check_grade_percent(round((homework_1_score + homework_2_score) / 2, 2)) + + def test_split_one_group_no_problems_group_1(self): + """ + Verifies students in the group that DOES have a problem receive a score for their problem. + """ + self.split_one_group_no_problems_setup(self.user_partition_group_1) + + self.submit_question_answer('H2P1', {'2_1': 'Correct'}) + + self.assertEqual(self.score_for_hw('homework1'), [1.0]) + self.assertEqual(self.score_for_hw('homework2'), [1.0]) + self.assertEqual(self.earned_hw_scores(), [1.0, 1.0]) + + # Grade percent is .75. Here is the calculation. + homework_1_score = 1.0 / 2 + homework_2_score = 1.0 / 1 + self.check_grade_percent(round((homework_1_score + homework_2_score) / 2, 2))