Testing auto_now_add DateTime fields with TestCase

I’m trying to use TestCase and setUpTestData() to create a test of a model. There are a couple of problems in the below code (marked with "TODO"s), but right now I’m just focusing on the datetime field one.

Essentially, I don’t know how to have the setUpTestData and the assertion be the same date/time since the “now” would always be just a little off between the “now” time when the test data is set up and the “now” time of the test being run. I originally tried defining a variable as a specific date/time (my “fake now”) and then assigning the variable to the date_added field, but that didn’t work because the auto_now_add field was still filled with the “real now” of when the setUpTestData was run (instead of the “fake now” of the variable).

Question
While trying to figure this out, I came across freezegun which looks like it’s addressing this problem. Before I try it out, I wanted to ask: is it normal to have to use something like freezegun (or another package) or is there a way Django users typically do this (without another package)? If people don’t usually use a package for this, how do you approach this? If people do usually use a package for this, is freezegun the standard way to go (or is there a different one that is common / best practice)?

tests.py

class CauseTests(TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.user = get_user_model().objects.create_user(
            username="testuser1",
            email="test@email.com",
            password="testpass123",
        )

        cls.cause = Cause.objects.create(
            #date_added is auto_now_add so it fills this field in automatically 
            cause_name="Cause Name",
            created_by=cls.user,
        )
        cls.cause.users_following_cause.add(cls.user) 

    # MODEL TESTS #################################################################
    def test_cause_model(self):
        #self.assertEqual(self.cause.date_added, ) TODO: figure out how to do the testing for "now" when the "now" of the creation and the "now" of the test is different
        self.assertEqual(self.cause.cause_name, "Cause Name")
        self.assertEqual(self.cause.created_by.username, "testuser1")
        self.assertEqual(self.cause.users_following_cause.count(), 1)
        self.assertEqual(self.cause.users_following_cause.filter(username="testuser1").exists(), True)
        self.assertEqual(str(self.cause), "Cause Name")
        #self.assertEqual(self.cause.get_absolute_url(), "/causes/1/")  # TODO: figure out how to do this when pk is UUID?

models.py

class Cause(models.Model):
    id = models.UUIDField( 
        primary_key=True,
        default=uuid.uuid4,
        editable=False)
    date_added = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
    cause_name = models.CharField(max_length=100)
    users_following_cause = models.ManyToManyField(CustomUser, related_name="causes_user_follows", blank=True)

There are many parts of this question that I can’t answer (because I don’t know), but there is one part I’d like to address:

When I’m writing tests, it’s my objective to only test my code. I don’t see any reason why I would test parts of the Django framework, as it’s my expectation that those components are already well-tested. What that means in this case is that I would never write a test to check the auto_now or auto_now_add fields, because I’m not implementing them.

If I’m looking to see that the field has been set, I’ll check for it not being null - or at most, that it is greater than a previously-saved value and less than the “current now” - but that would be an extremely unusual situation for me.

Note: This principle holds true for everything I test, not just datetime fields. I don’t test that integer primary keys are monotonically increasing. I don’t test that exceptions are thrown if a database field is assigned an improper value, like trying to save 100 characters in a field defined with max_length=50. I try to be very intentional with what I do test, ensuring that I’m only testing what I need to test, and not testing what’s not my problem.

AKA: a valid reason to do a little less work…yes, please! :stuck_out_tongue_winking_eye:

The reasoning (avoiding duplicate effort / wasted time etc) behind this guideline to just test “my” code makes a lot of sense. Thanks for going into detail about your thinking here; it’s appreciated.