pythonunit-testingdjango-unittestunittest2

How to test methods that compute relative time in python using unitttest?


I have a method in a django model that does a computation relative to the current time. Here is a snippet:

def next_date():
    now = datetime.now()
    trial_expires = max(self.date_status_changed + timedelta(self.trial_days), now)
    return timezone.datetime(trial_expires.year, trial_expires.month+1, 1, tzinfo=trial_expires.tzinfo)

What's the proper way to test this in django/python using unittest? What I'd like to do is be able to hard code some values for "now" in the test so I can try the various edge cases. Ideally, I'd like to avoid relying on the current time and date in the test.

One approach would be to modify my method to accept an optional parameter that would override the 'now' value it uses. Does python have any functions to do something similar without having to modify my method signature?


Solution

  • You could extract datetime.now() as a parameter:

    def next_date(nowfunc=datetime.now):
        now = nowfunc()
        ...
    

    or as a class' dependency:

    class X:
        def __init__(self, nowfunc=datetime.now):
            self._nowfunc = nowfunc
    
    def next_date(self):
        now = self._nowfunc()
        ...
    

    And pass a mock function with the required result from your tests.

    But if you don't want to modify the signature, use patches:

    @patch.object(datetime, 'now')
    def test_next_date(self, nowfunc):
        nowfunc.return_value = ... # required result
        # the rest of the test