datetime.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)
이 부분은 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)
False이지만 :
isinstance(datetime.datetime(2014, 04, 01, 14, 0, 0), datetime.date)
진정한 따라서되는 datetime.datetime
개체는 변환됩니다 datetime.date
, 당신은 검색 할 때 u2.last_login
는 SQL에서 값이 실제로 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 장고와 함께 작동하는.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다