gpt4 book ai didi

python - 在 Django 单元测试中修补日期时间的最佳方法

转载 作者:太空宇宙 更新时间:2023-11-03 11:04:50 35 4
gpt4 key购买 nike

我正在使用自制的 datetime.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:

def to_python(self, value):
if value is None:
return value
if isinstance(value, datetime.datetime):
return value
if isinstance(value, datetime.date):
value = datetime.datetime(value.year, value.month, value.day)

Source

这部分在您在测试中调用 u.save() 时执行。由于 value (u.last_login) 的 Django 代码值中的这一点是 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)

为 True 因此 datetime.datetime 对象被转换为datetime.date,当您从 SQL 中检索 u2.last_login 时,该值为实际上是 datetime(2014, 04, 01, 0, 0, 0) 而不是 datetime(2014, 04, 01, 14, 0, 0)

因此测试失败。

解决这个问题的方法是替换:

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

谢谢!

最佳答案

https://github.com/spulec/freezegun与 Django 一起工作。

关于python - 在 Django 单元测试中修补日期时间的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22787596/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com