我正在使用一个自制的datetime.datetime
mock来修补代码中的datetime(请参阅最下面的部分),但是其他人似乎在理解其工作原理时遇到了问题,并遇到了意想不到的问题。考虑以下测试:
@patch("datetime.datetime", FakeDatetime)
def my_test(self):
FakeDatetime.now_value = datetime(2014, 04, 02, 13, 0, 0)
u = User.objects.get(x=y)
u.last_login = datetime(2014, 04, 01, 14, 0, 0)
u.save()
u2 = User.objects.get(x=y)
# Checks if datetime.datetime.now() - u2.last_login < 24 hours
self.assertTrue(u2.logged_in_in_last_24_hours())
现在,如果您看看Django DatetimeField是如何将日期序列化为SQL的:
^{pr2}$此部分在测试中调用u.save()
时执行。
由于Django代码值value
(u.last_login
)中的这一点是datetime.datetime
类型的,因为我们在测试中使用了未匹配版本的datetime(因为我们的导入是
在模块级别,修补程序在方法级别)。在
现在在Django代码中,datetime.datetime
被修补,因此:
isinstance(value, datetime.datetime)
相当于:
isinstance(datetime.datetime(2014, 04, 01, 14, 0, 0), FakeDatetime)
这是错误的,但是:
isinstance(datetime.datetime(2014, 04, 01, 14, 0, 0), datetime.date)
,因此datetime.datetime
对象被转换为
datetime.date
,当您从SQL中检索{
因此测试失败了。在
解决方法是替换:
u.date_joined = datetime(2014, 04, 01, 14, 0, 0)
有:
u.date_joined = FakeDatetime(2014, 04, 01, 14, 0, 0)
但这似乎很容易出错,并且容易使使用或编写测试的人感到困惑。在
尤其是在需要实数now
值的情况下,必须执行datetime_to_fakedatetime(datetime.datetime.now())
或调用FakeDatetime.now()
,但要确保之前的测试已取消FakeDatetime.now_value
。在
我正在寻找一种方法使其更直观,但同时避免在特定的子模块中修补datetime.datetime
对象(因为可能有许多子模块),只需在整个代码中修补它。在
自制模拟代码:
from datetime import datetime
class FakeDatetime(datetime):
now_value = None
def __init__(self, *args, **kwargs):
return super(FakeDatetime, self).__init__()
@classmethod
def now(cls):
if cls.now_value:
result = cls.now_value
else:
result = datetime.now()
return datetime_to_fakedatetime(result)
@classmethod
def utcnow(cls):
if cls.now_value:
result = cls.now_value
else:
result = datetime.utcnow()
return datetime_to_fakedatetime(result)
# http://stackoverflow.com/questions/20288439/how-to-mock-the-operator-in-python-specifically-datetime-date-datetime-ti
def __add__(self, other):
return datetime_to_fakedatetime(super(FakeDatetime, self).__add__(other))
def __sub__(self, other):
return datetime_to_fakedatetime(super(FakeDatetime, self).__sub__(other))
def __radd__(self, other):
return datetime_to_fakedatetime(super(FakeDatetime, self).__radd__(other))
def __rsub__(self, other):
return datetime_to_fakedatetime(super(FakeDatetime, self).__rsub__(other))
def datetime_to_fakedatetime(dt):
# Because (datetime - datetime) produces a timedelta, so check if the result is of the correct type.
if isinstance(dt, datetime):
return FakeDatetime(
dt.year,
dt.month,
dt.day,
dt.hour,
dt.minute,
dt.second,
dt.microsecond,
dt.tzinfo
)
return dt
谢谢!在
有一个与Django一起工作的https://github.com/spulec/freezegun。在
相关问题 更多 >
编程相关推荐