Testing a time-dependent method
<p>I have a method that takes a datetime and returns what period of time this datetime belongs to, for example "yesterday" or "a month ago".</p>

<pre><code>from datetime import datetime


def tell_time_ago(basetime):
    difference = datetime.now() - basetime

    days = difference.days
    seconds = difference.seconds
    hours = seconds / 3600
    minutes = seconds / 60

    if days and days == 1:
        return 'Yesterday'
    elif days and days != 1 and days &lt; 7:
        return '%s days ago' % days
    elif days and days != 1 and 7 &lt; days &lt; 31:
        return 'Within this month'
    elif days and days != 1 and 30 &lt; days &lt; 365:
        return '%s months ago' % (days / 30)
    elif days and days != 1 and 365 &lt;= days &lt; 730:
        return 'A year ago'
    elif days and days != 1 and days &gt;= 730:
        return '%s years ago' % (days / 365)

    elif hours and hours == 1:
        return 'An hour ago'
    elif hours and hours != 1:
        return '%s hours ago' % hours

    elif minutes and minutes == 1:
        return 'A minute ago'
    elif minutes and minutes != 1:
        return '%s minutes ago' % minutes

    elif seconds and seconds == 1:
        return 'A second ago'
    elif seconds and seconds != 1:
        return '%s seconds ago' % seconds

    else:
        return '0 second ago'
</code></pre>

<p>I want to extend this method so I'm going to write tests for it. If want to write a test for this method, should I change the current date of system to a specific date and revert it back to normal every time, so the test won't fail just because the date is changed? For example:</p>

<pre><code>class TestCase(unittest.TestCase):
    def test_timedelta(self):
        a_year_ago = datetime(2015, 5, 12, 23, 15, 15, 53000)
        assert tell_time_ago(a_year_ago) == 'A year ago'
</code></pre>

<p>If I run this test two years from now, it will fail. What is the best approach?</p>

<p>In general, I think it's a good idea to make your nontrivial functions and classes as close to mathematical functions (e.g., <code>sin(x)</code>), as possible. Given the same input, a mathematical function gives the same output each time, irrespective of the current date, random choices, and so forth. </p>

<ul>
<li><p>If your function performs nontrivial logic dependent on the current date or time, pass the current date or time externally to it.</p></li>
<li><p>If your function performs random choices, pass it a pseudo-random number generator.</p></li>
</ul>

<p>So, for example, instead of:</p>

<pre><code>import datetime

def foo():
    ...
    now = datetime.datetime.now()
    ...

foo()
</code></pre>

<p>Use </p>

<pre><code>import datetime

def foo(now):
    ...
    ...

foo(datetime.datetime.now())
</code></pre>

<p>This makes your nontrivial code consistent across multiple executions.</p>

<ol>
<li><p>You can predictably test it.</p></li>
<li><p>If it fails in production, it is easier to reconstruct the problem.</p></li>
</ol>

python unit-testing