0

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?

1 Answer 1

1

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
Sign up to request clarification or add additional context in comments.

3 Comments

Well, that's exactly what @patch does (btw, mock is really a useful library, irreplaceable for the proper TDD). But I personally prefer using an explicit dependency, since then you make your test slightly less dependent on the method internals (namely, on which functions it uses), which is a sign of a better design.
Could you clarify what do you mean by "explicit dependency"?
I mean, you can pass the dependency explicitly from the outside via a method/constructor argument (Dependency Inversion) or as a class attribute, then you're free to replace it with whatever you want, e.g. for testing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.