jeudi 22 octobre 2020

Django Model Mocking - Better to create model or mock model for testing?

I have a very simple model like this:

class Observation(models.Model):
    thing = models.ForeignKey(Thing, on_delete=models.PROTECT)
    user_locked = models.BooleanField(default=False)
    admin_locked = models.BooleanField(default=False)
    created = models.DateTimeField(auto_now=False, auto_now_add=True)
    created_by = models.ForeignKey(
        User, on_delete=models.PROTECT, related_name="%(class)s_created_by"
    )
    updated = models.DateTimeField(auto_now=True, auto_now_add=False)
    updated_by = models.ForeignKey(
        User, on_delete=models.PROTECT, related_name="%(class)s_updated_by"
    )

    def is_fully_locked(self):
        """Return boolean if Observation is locked by both"""
        if self.user_locked and self.admin_locked:
            return True
        return False

I'm trying to test the is_fully_locked() method and I was curious about creating the Observation model.

I have used things like Mixer and factory_boy in the past to create objects to test against, but as those projects grew so did the time it took for the tests to run which I'd like to avoid. I have recently started reading about using Mock (I'm still confused by it a little).

My question is - for a simple model like this - what is the best/fastest way to test that method?

Currently I have some test like this:

class ObservationTest(TestCase):
    def test_is_fully_locked_with_no_employee_locked(self):
        start = time.time()
        observation = Observation(admin_locked=True)
        print(time.time() - start)
        # Takes 5.91278076171875e-05
        # FASTEST
        self.assertFalse(observation.is_fully_locked())

    def test_is_fully_locked_with_no_employee_locked_mixer(self):
        start = time.time()
        observation = mixer.blend(Observation, admin_locked=True)
        print(time.time() - start)
        # Takes 0.011276006698608398
        # SLOWEST
        self.assertFalse(observation.is_fully_locked())

    def test_is_fully_locked_with_no_employee_locked_mock(self):
        start = time.time()
        observation = mock.Mock(spec=Observation)
        observation.admin_locked = True
        print(time.time() - start)
        # Takes 0.0005071163177490234
        # SECOND FASTEST - but errors out
        self.assertFalse(observation.is_fully_locked())
        # This assertion fails: AssertionError: <Mock name='mock.is_fully_locked()' id='4545690352'> is not false

I am also curious - are these each valid ways to test this? I know the mixer method works - but it touches the database, which I believe you're supposed to avoid (and it's probably why it's the slowest).

Questions are as follows:

  • Is the fastest method above acceptable for testing?

  • Of the three tests - which would be the 'best practice' - or are all of them acceptable?

  • With the mock test - how would I write that test to pass (i.e. what did I do wrong)?

Aucun commentaire:

Enregistrer un commentaire