编辑:由于我的答案是这里公认的答案,我正在更新它,让每个人都知道同时创建了一个更好的方法,freezegun 库:https ://pypi.python.org/pypi/freezegun 。当我想影响测试时间时,我会在所有项目中使用它。看看它。
原答案:
像这样更换内部的东西总是很危险的,因为它可能会产生令人讨厌的副作用。所以你真正想要的是让猴子补丁尽可能地本地化。
我们使用 Michael Foord 的优秀模拟库:http ://www.voidspace.org.uk/python/mock/有一个@patch
装饰器可以修补某些功能,但是猴子补丁只存在于测试功能的范围内,一切都是函数超出范围后自动恢复。
唯一的问题是内部datetime
模块是用 C 语言实现的,所以默认情况下您无法对其进行修补。我们通过制作我们自己的可以模拟的简单实现来解决这个问题。
整个解决方案是这样的(示例是在 Django 项目中使用的验证器函数,用于验证日期是否在未来)。请注意,我从一个项目中取出了这个,但取出了不重要的东西,所以在复制粘贴时,事情可能实际上不起作用,但你明白了,我希望 :)
datetime.date.today
首先,我们在一个名为的文件中定义我们自己的非常简单的实现utils/date.py
:
import datetime
def today():
return datetime.date.today()
然后我们为这个验证器创建单元测试tests.py
:
import datetime
import mock
from unittest2 import TestCase
from django.core.exceptions import ValidationError
from .. import validators
class ValidationTests(TestCase):
@mock.patch('utils.date.today')
def test_validate_future_date(self, today_mock):
# Pin python's today to returning the same date
# always so we can actually keep on unit testing in the future :)
today_mock.return_value = datetime.date(2010, 1, 1)
# A future date should work
validators.validate_future_date(datetime.date(2010, 1, 2))
# The mocked today's date should fail
with self.assertRaises(ValidationError) as e:
validators.validate_future_date(datetime.date(2010, 1, 1))
self.assertEquals([u'Date should be in the future.'], e.exception.messages)
# Date in the past should also fail
with self.assertRaises(ValidationError) as e:
validators.validate_future_date(datetime.date(2009, 12, 31))
self.assertEquals([u'Date should be in the future.'], e.exception.messages)
最终实现如下所示:
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ValidationError
from utils import date
def validate_future_date(value):
if value <= date.today():
raise ValidationError(_('Date should be in the future.'))
希望这可以帮助