def setup(self, db): self.course_enrollment = CourseEnrollmentFactory() if OPENEDX_RELEASE == GINKGO: self.course_id = self.course_enrollment.course_id else: self.course_id = self.course_enrollment.course.id self.lcg = LearnerCourseGrades(self.course_enrollment.user.id, self.course_id) # set up our sections # This is a quick job. We can do it cleaner # We do want to label each subsection grade # to make it easier to identify them in the # tests self.msg1 = MockSubsectionGrade(tw_earned=0.0, tw_possible=0.0), self.msg2 = MockSubsectionGrade(tw_earned=0.0, tw_possible=0.5) self.msg3 = MockSubsectionGrade(tw_earned=0.5, tw_possible=1.0) self.graded_sections = [self.msg2, self.msg3] self.all_sections = [self.msg1, self.msg2, self.msg3] self.lcg.course_grade.chapter_grades = OrderedDict( alpha=dict( sections=[self.msg1], url_name=u'ec7e84694fca2d073731a462a5916a7a', display_name=u'Module 1 - Overview', ), bravo=dict( sections=[self.msg2, self.msg3], url_name=u'2f43c0b7da59ed40156155f9a8ca4d40', display_name=u'Module 2 - First Principles', ))
def _collect_progress_data(student_module): """Get new progress data for the learner/course Uses `figures.metrics.LearnerCourseGrades` to retrieve progress data via `CourseGradeFactory().read(...)` and calculate progress percentage """ lcg = LearnerCourseGrades(user_id=student_module.student_id, course_id=student_module.course_id) course_progress_details = lcg.progress() return course_progress_details
def test_lcg_course_progress(): ''' This is a basic test. We want to expand on it to create specific mock values returned by CourseGradeFactory (assigned to LearnerCourseGrades course_grade.chapter_grades attributes) The expected data are pulled from the hardcoded values in the mocks. See ``tests/mocks/lms/djangoapps/grades/course_grade.py`` ''' expected = dict(progress_percent=0.5, course_progress_details=dict( count=2, sections_worked=1, points_possible=1.5, points_earned=0.5, )) course_enrollment = CourseEnrollmentFactory() course_progress = LearnerCourseGrades.course_progress(course_enrollment) assert course_progress == expected
class TestLearnerCourseGrades(object): @pytest.fixture(autouse=True) def setup(self, db): self.course_enrollment = CourseEnrollmentFactory() if OPENEDX_RELEASE == GINKGO: self.course_id = self.course_enrollment.course_id else: self.course_id = self.course_enrollment.course.id self.lcg = LearnerCourseGrades(self.course_enrollment.user.id, self.course_id) # set up our sections # This is a quick job. We can do it cleaner # We do want to label each subsection grade # to make it easier to identify them in the # tests self.msg1 = MockSubsectionGrade(tw_earned=0.0, tw_possible=0.0), self.msg2 = MockSubsectionGrade(tw_earned=0.0, tw_possible=0.5) self.msg3 = MockSubsectionGrade(tw_earned=0.5, tw_possible=1.0) self.graded_sections = [self.msg2, self.msg3] self.all_sections = [self.msg1, self.msg2, self.msg3] self.lcg.course_grade.chapter_grades = OrderedDict( alpha=dict( sections=[self.msg1], url_name=u'ec7e84694fca2d073731a462a5916a7a', display_name=u'Module 1 - Overview', ), bravo=dict( sections=[self.msg2, self.msg3], url_name=u'2f43c0b7da59ed40156155f9a8ca4d40', display_name=u'Module 2 - First Principles', )) def test_str_rep(self): '''Test the string representation, __str__ ''' assert self.lcg.__str__() def test_chapter_grades(self): '''Tests the 'chapter_grades' property Because course grades are mocked, we are not interested in inspecting the contents of 'chapter_grades' This test was written when the chapter_grades were defined in the mocks. Since then we define them here to better control the values/structure for these tests and provide immediate (Same source file) context for the data used in these tests ''' assert isinstance(self.lcg.chapter_grades, dict) # get the sub-dict of the first key keys = list(self.lcg.chapter_grades.keys()) assert set(self.lcg.chapter_grades[keys[0]].keys()) == set( ['sections', 'url_name', 'display_name']) def test_certificate_and_completion(self): ''' We're testing both certificate completion because currently, the only way to tell if a user ''' # We shouldn't have any certificates for this # course enrollment assert not self.lcg.certificates() assert not self.lcg.learner_completed() # Create a certificate record for this user expected_cert = GeneratedCertificateFactory( user=self.lcg.learner, course_id=self.lcg.course.id, created_date=datetime.datetime(2018, 6, 1, tzinfo=utc)) assert expected_cert check_certs = self.lcg.certificates() assert check_certs.count() == 1 assert check_certs[0] == expected_cert assert self.lcg.learner_completed() @pytest.mark.parametrize('tw_earned, tw_possible, check', [ (0.0, 0.0, False), (0.0, 0.5, True), (0.5, 1.0, True), ]) def test_is_section_graded(self, tw_earned, tw_possible, check): '''Validates the check if a section is graded Method does not rely on class instance values ''' section = MockSubsectionGrade(tw_earned=tw_earned, tw_possible=tw_possible) assert self.lcg.is_section_graded(section) == check # # The following two tests test retrieving sections from chapter grades # # We have two methods instead of parametrizing for simplicity and that # decorators can't accept class instance variables for the class method # for which the decorator is applied. We would have to build our test # data outside of the class def test_sections_all(self): ''' LearnerCourseGrade.sections_list uses the 'sections' iterator method so we can test both with the 'sections_list' method ''' sections = self.lcg.sections_list() assert set(sections) == set(self.all_sections) sections = self.lcg.sections_list(only_graded=False) assert set(sections) == set(self.all_sections) def test_sections_graded(self): sections = self.lcg.sections_list(only_graded=True) assert set(sections) == set(self.graded_sections) def test_progress(self): progress = self.lcg.progress() expected = dict(count=len(self.graded_sections), points_possible=sum(rec.all_total.possible for rec in self.graded_sections), points_earned=sum(rec.all_total.earned for rec in self.graded_sections), sections_worked=len([ rec for rec in self.graded_sections if rec.all_total.earned > 0 ])) assert progress == expected expected_progress_percent = float(expected['sections_worked']) / float( expected['count']) assert self.lcg.progress_percent() == expected_progress_percent assert self.lcg.progress_percent(expected) == expected_progress_percent def test_progress_percent_no_count(self): ''' This test makes sure that we don't get a divide by zero error in the progress percent ''' progress_details = dict( count=0, points_possible=0.0, points_earned=0.0, sections_worked=0, ) assert self.lcg.progress_percent(progress_details) == 0.0