Home > Enterprise >  Django testing doesn't recognize dirty_fields?
Django testing doesn't recognize dirty_fields?

Time:08-27

One of my models uses dirty_fields. The save method detects when the field scale_mode changes. Once this happens, it goes through all the related grade objects and changes the field score for each affected grade. The goal is if VSB is swapped with VSBPLUS, then APP is swapped with APP .

model:

class GradeBookSetup(DirtyFieldsMixin, models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL, on_delete=CASCADE)

    VSB = 'VSB'
    VSBPLUS = 'VSBPLUS'
    SCALEMODE = [
        ('VSB', 'BEG DEV APP EXT'),
        ('VSBPLUS', 'BEG DEV APP APP  EXT'),
    ]

    scale_mode = models.CharField(
        max_length=7, choices=SCALEMODE, blank=True, default=VSB)

    def save(self, *args, **kwargs):
        super(GradeBookSetup, self).save(*args, **kwargs)
        if self.is_dirty():
            dirty_fields = self.get_dirty_fields()
            if 'scale_mode' in dirty_fields:
                if self.scale_mode == "VSB":
                    n = 0
                    objs = Grade.objects.filter(user=self.user)
                    for grade in objs:
                        if grade.score == "APP ":
                            objs[n].score = "APP"
                            n = n   1
                    Grade.objects.bulk_update(objs, ['score'])
                elif self.scale_mode == "VSBPLUS":
                    objs = Grade.objects.filter(user=self.user)
                    for grade in objs:
                        if grade.score == "APP":
                            objs[n].score = "APP "
                    Grade.objects.bulk_update(objs, ['score'])

class Grade(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

    INCOMPLETE = 'I'
    BEGINNING = 'BEG'
    DEVELOPING = 'DEV'
    APPLYING = 'APP'
    APPLYINGPLUS = 'APP '
    EXTENDING = 'EXT'

    score = models.CharField(
        max_length=4, blank=True, default=INCOMPLETE)
    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             on_delete=models.CASCADE)
    assessment = models.ForeignKey(
        Assessment, on_delete=models.CASCADE, null=True, blank=True)
    objective = models.ForeignKey(
        Objective, on_delete=models.CASCADE, blank=True)
    student = models.ForeignKey(Student, on_delete=models.CASCADE)
    cblock = models.ForeignKey(Classroom, on_delete=models.CASCADE, default=1)

I am writing tests for this model. Each of the test below passes except for the last test, test_scale_mode_change.

class GradeBookSetupTest(TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.user = get_user_model().objects.create_user(
            username='tester',
            email='[email protected]',
            password='tester123'
        )

        cls.gbsetup = GradeBookSetup(
            user=cls.user,
            scale_mode="VSBPLUS",
        )
        cls.gbsetup.save()
        
        cls.student = Student.objects.create(
            user=student_user,
            student_first="Jim",
            student_last="Smith",
            nickname="Jim S",
            fullname="Jim Smith",
            student_number=992342,
            email="[email protected]"
        )
        cls.course = Course.objects.create(
            user=cls.user,
            course_name="Math8",
            grade_level='ELEM',

        )
        cls.classroom = Classroom(
            user=cls.user,
            classroom_name='Block 1',
            course=cls.course,
        )
        cls.classroom.students.add(cls.student)
        cls.classroom.save()

        cls.objective = Objective.objects.create(
            user=cls.user,
            objective_name='factor.1',
            mode='LA',
            course=cls.course,
            description="Test objective",
        )
        cls.assessment = Assessment(
            user=cls.user,
            assessment_name="Quiz1",
            course=cls.course,
        )
        cls.assessment.objectives.add(cls.objective)
        cls.assessment.save()

        cls.grade = Grade.objects.create(
            user=cls.user,
            score='APP ',
            student=cls.student,
            cblock=cls.classroom,
            assessment=cls.assessment,
            objective=cls.objective
        )

    def test_gradebooksetup_creation(self):
        self.assertEqual(self.gbsetup.scale_mode, "VSBPLUS")
        
    def test_grade_creation(self):
        self.assertEqual(self.grade.score, 'APP ')
        self.assertNotEqual(self.grade.score, 'DEV')

    def test_scale_mode_change(self):
        self.gbsetup.scale_mode = 'VSB'
        self.gbsetup.save()
        print(self.gbsetup.scale_mode)
        self.assertEqual(self.grade.score, 'APP')

What I expect to happen is that `self.gbsetup.scale_mode = 'VSB' should trigger the dirty_field in the save method. This should then change the APP score to APP. The print statement confirms that gbsetup == VSB. In practice, my app does perform this function correctly.

What happens though is:

self.assertEqual(self.grade.score, 'APP')
AssertionError: 'APP ' != 'APP'

I didn't show all the related models for Grade and GradeBookSetup, I don't think they are relevant to this problem. I can add these if required.

CodePudding user response:

You might need to regrab the grade from the database as the change is made in the DB but the reference instance is still the one created in the setup.

def test_scale_mode_change(self):
    self.gbsetup.scale_mode = 'VSB'
    self.gbsetup.save()
    print(self.gbsetup.scale_mode)
    #we have made indirect changes to grade via the gbsetup.save() function that we need to check
    self.grade.refresh_from_db()
    self.assertEqual(self.grade.score, 'APP')
  • Related