test_spoc_gradebook.py 6.29 KB
Newer Older
1
"""
2
Tests of the instructor dashboard spoc gradebook
3 4 5
"""

from django.core.urlresolvers import reverse
6
from nose.plugins.attrib import attr
7

8 9
from capa.tests.response_xml_factory import StringResponseXMLFactory
from courseware.tests.factories import StudentModuleFactory
10
from lms.djangoapps.grades.tasks import compute_all_grades_for_course
11 12 13
from student.tests.factories import AdminFactory, CourseEnrollmentFactory, UserFactory
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
14 15 16

USER_COUNT = 11

Miles Steele committed
17

18
@attr(shard=1)
19
class TestGradebook(SharedModuleStoreTestCase):
20 21 22 23 24
    """
    Test functionality of the spoc gradebook. Sets up a course with assignments and
    students who've scored various scores on these assignments. Base class for further
    gradebook tests.
    """
25 26
    grading_policy = None

27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
    @classmethod
    def setUpClass(cls):
        super(TestGradebook, cls).setUpClass()

        # Create a course with the desired grading policy (from our class attribute)
        kwargs = {}
        if cls.grading_policy is not None:
            kwargs['grading_policy'] = cls.grading_policy
        cls.course = CourseFactory.create(**kwargs)

        # Now give it some content
        with cls.store.bulk_operations(cls.course.id, emit_signals=False):
            chapter = ItemFactory.create(
                parent_location=cls.course.location,
                category="sequential",
            )
            section = ItemFactory.create(
                parent_location=chapter.location,
                category="sequential",
                metadata={'graded': True, 'format': 'Homework'}
            )
            cls.items = [
                ItemFactory.create(
                    parent_location=section.location,
                    category="problem",
                    data=StringResponseXMLFactory().build_xml(answer='foo'),
                    metadata={'rerandomize': 'always'}
                )
                for __ in xrange(USER_COUNT - 1)
            ]

58
    def setUp(self):
59 60
        super(TestGradebook, self).setUp()

61 62
        instructor = AdminFactory.create()
        self.client.login(username=instructor.username, password='test')
63
        self.users = [UserFactory.create() for _ in xrange(USER_COUNT)]
64 65 66 67

        for user in self.users:
            CourseEnrollmentFactory.create(user=user, course_id=self.course.id)

68
        for i, item in enumerate(self.items):
69 70 71 72 73 74
            for j, user in enumerate(self.users):
                StudentModuleFactory.create(
                    grade=1 if i < j else 0,
                    max_grade=1,
                    student=user,
                    course_id=self.course.id,
75
                    module_state_key=item.location
76
                )
77
        compute_all_grades_for_course.apply_async(kwargs={'course_key': unicode(self.course.id)})
78

79
        self.response = self.client.get(reverse(
80
            'spoc_gradebook',
81 82
            args=(self.course.id.to_deprecated_string(),)
        ))
83 84 85

        self.assertEquals(self.response.status_code, 200)

Miles Steele committed
86

87
@attr(shard=1)
88
class TestDefaultGradingPolicy(TestGradebook):
89 90 91 92
    """
    Tests that the grading policy is properly applied for all users in the course
    Uses the default policy (50% passing rate)
    """
93 94
    def test_all_users_listed(self):
        for user in self.users:
95
            self.assertIn(user.username, unicode(self.response.content, 'utf-8'))
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111

    def test_default_policy(self):
        # Default >= 50% passes, so Users 5-10 should be passing for Homework 1 [6]
        # One use at the top of the page [1]
        self.assertEquals(7, self.response.content.count('grade_Pass'))

        # Users 1-5 attempted Homework 1 (and get Fs) [4]
        # Users 1-10 attempted any homework (and get Fs) [10]
        # Users 4-10 scored enough to not get rounded to 0 for the class (and get Fs) [7]
        # One use at top of the page [1]
        self.assertEquals(22, self.response.content.count('grade_F'))

        # All other grades are None [29 categories * 11 users - 27 non-empty grades = 292]
        # One use at the top of the page [1]
        self.assertEquals(293, self.response.content.count('grade_None'))

Miles Steele committed
112

113
@attr(shard=1)
114
class TestLetterCutoffPolicy(TestGradebook):
115 116 117 118
    """
    Tests advanced grading policy (with letter grade cutoffs). Includes tests of
    UX display (color, etc).
    """
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
    grading_policy = {
        "GRADER": [
            {
                "type": "Homework",
                "min_count": 1,
                "drop_count": 0,
                "short_label": "HW",
                "weight": 1
            },
        ],
        "GRADE_CUTOFFS": {
            'A': .9,
            'B': .8,
            'C': .7,
            'D': .6,
        }
    }

    def test_styles(self):

        self.assertIn("grade_A {color:green;}", self.response.content)
        self.assertIn("grade_B {color:Chocolate;}", self.response.content)
        self.assertIn("grade_C {color:DarkSlateGray;}", self.response.content)
        self.assertIn("grade_D {color:DarkSlateGray;}", self.response.content)

    def test_assigned_grades(self):
        # Users 9-10 have >= 90% on Homeworks [2]
        # Users 9-10 have >= 90% on the class [2]
        # One use at the top of the page [1]
        self.assertEquals(5, self.response.content.count('grade_A'))

        # User 8 has 80 <= Homeworks < 90 [1]
        # User 8 has 80 <= class < 90 [1]
        # One use at the top of the page [1]
        self.assertEquals(3, self.response.content.count('grade_B'))

        # User 7 has 70 <= Homeworks < 80 [1]
        # User 7 has 70 <= class < 80 [1]
        # One use at the top of the page [1]
        self.assertEquals(3, self.response.content.count('grade_C'))

        # User 6 has 60 <= Homeworks < 70 [1]
        # User 6 has 60 <= class < 70 [1]
        # One use at the top of the page [1]
        self.assertEquals(3, self.response.content.count('grade_C'))

        # Users 1-5 have 60% > grades > 0 on Homeworks [5]
        # Users 1-5 have 60% > grades > 0 on the class [5]
        # One use at top of the page [1]
        self.assertEquals(11, self.response.content.count('grade_F'))

        # User 0 has 0 on Homeworks [1]
        # User 0 has 0 on the class [1]
        # One use at the top of the page [1]
173
        self.assertEquals(3, self.response.content.count('grade_None'))