This is because today is an attribute. In python, we can override
attribute access to become a function call. I don't have python right
now, but try this:
del date.today
date.today = mytoday
> A second possibility would be to change the system date (I am running
> Linux). However the standard Python module doesn't provide a method for this
> purpose. I could use os.system to issue a date command. But I am not very
> comfortable with this since changing the system time could break something
> undesirably. Also I will then have to have root privilege to run my test.
> Besides, I will have to stop the ntp daemon so it will not inadvertently
> correct the system clock during the test period.
>
> Is there any suggestion from the community on how best to test such
> functions?
It is a very bad idea to change the system date.
It won't work. The datetime module is written in C. You can't modify a C
extension.
Christian
Hmm. Given that, Lie, maybe what you need to do is modify your code
so that you call your own special purpose function to get 'today',
and replace _that_ for testing, using datetime's today for production.
--RDM
> In my project I have several date related methods which I want tested for
> correctness. The functions use date.today() in several places. Since this
> could change every time I run the test, I hope to find someway to fake a
> date.today.
>
> For illustration lets say I have a function:
>
>
> from datetime import date
> def today_is_2009():
> return date.today().year == 2009
>
> To test this I would like to write test function like:
>
> def test_today_is_2009():
> set_today(date(2008, 12, 31))
> assert today_is_2009() == False
> set_today(date(2009,1,1))
> assert today_is_2009() == True
>
Instead of trying to inject a fake date, you could rewrite the function to
take a date argument:
def today_is_2009(today=None):
if today is None:
today = date.today()
return today.year == 2009
Then, tests should pass a known date. This approach has a drawback -- you
don't test the case when no argument is given.
Another way is to use a fake date class, or a fake datetime module. Google
"python mock object"
--
Gabriel Genellina
class FakeDate(object):
def __init__(self, value):
self._result = value
def today(self):
return self._result
def test_today_is_2009_too_old():
temp, sut.date = sut.date, FakeDate(date(2008, 12, 31))
try:
assert not sut.today_is_2009()
finally:
sut.date = temp
def test_today_is_2009_too_young():
temp, sut.date = sut.date, FakeDate(date(2010, 1, 1))
try:
assert not sut.today_is_2009()
finally:
sut.date = temp
def test_today_is_2009_just_right():
temp, sut.date = sut.date, FakeDate(date(2009, 1, 1))
try:
assert not sut.today_is_2009()
finally:
sut.date = temp
Note: each test should test 1 thing.
--Scott David Daniels
Scott....@Acm.Org
Although you can't override today, you should be able to do something
along the lines of:
class MyDate(object):
def __init__(self, today):
self.today = today
my_date = MyDate(date(2009, 11, 12))
date = my_date
This assumes you aren't using anything else from date. If you are
you'll either have to add that to MyDate or use a proper Mock Object.
Ed