왜 이것이 작동하지 않는지 말해 줄 수 있습니까?
>>> import mock
>>> @mock.patch('datetime.date.today')
... def today(cls):
... return date(2010, 1, 1)
...
>>> from datetime import date
>>> date.today()
datetime.date(2010, 12, 19)
누군가 더 나은 방법을 제안 할 수 있습니까?
답변
몇 가지 문제가 있습니다.
우선, 당신이 사용하는 방식이 mock.patch
옳지 않습니다. 데코레이터로 사용될 때 주어진 함수 / 클래스 (이 경우 datetime.date.today
) 는 데코 레이팅 된 함수 내에서만Mock
객체로 대체합니다 . 그래서, 단지 내 것이다 당신이 원하는 것처럼 보이지 않는 다른 기능을합니다.today()
datetime.date.today
정말로 원하는 것은 다음과 같습니다.
@mock.patch('datetime.date.today')
def test():
datetime.date.today.return_value = date(2010, 1, 1)
print datetime.date.today()
불행히도 이것은 작동하지 않습니다.
>>> test()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "build/bdist.macosx-10.6-universal/egg/mock.py", line 557, in patched
File "build/bdist.macosx-10.6-universal/egg/mock.py", line 620, in __enter__
TypeError: can't set attributes of built-in/extension type 'datetime.date'
파이썬 내장 타입은 불변이기 때문에 실패합니다- 자세한 내용 은 이 답변 을 참조하십시오.
이 경우 datetime.date를 직접 서브 클래스하고 올바른 함수를 만듭니다.
import datetime
class NewDate(datetime.date):
@classmethod
def today(cls):
return cls(2010, 1, 1)
datetime.date = NewDate
그리고 지금 당신은 할 수 있습니다 :
>>> datetime.date.today()
NewDate(2010, 1, 1)
답변
또 다른 옵션은 https://github.com/spulec/freezegun/ 을 사용하는 것입니다
설치하십시오 :
pip install freezegun
그리고 그것을 사용하십시오 :
from freezegun import freeze_time
@freeze_time("2012-01-01")
def test_something():
from datetime import datetime
print(datetime.now()) # 2012-01-01 00:00:00
from datetime import date
print(date.today()) # 2012-01-01
또한 다른 모듈의 메소드 호출에서 다른 날짜 및 시간 호출에 영향을줍니다.
other_module.py :
from datetime import datetime
def other_method():
print(datetime.now())
main.py :
from freezegun import freeze_time
@freeze_time("2012-01-01")
def test_something():
import other_module
other_module.other_method()
그리고 마지막으로:
$ python main.py
# 2012-01-01
답변
가치있는 것을 위해 Mock 문서는 datetime.date.today에 대해 구체적으로 이야기하며 더미 클래스를 만들지 않고도이 작업을 수행 할 수 있습니다.
https://docs.python.org/3/library/unittest.mock-examples.html#partial-mocking
>>> from datetime import date
>>> with patch('mymodule.date') as mock_date:
... mock_date.today.return_value = date(2010, 10, 8)
... mock_date.side_effect = lambda *args, **kw: date(*args, **kw)
...
... assert mymodule.date.today() == date(2010, 10, 8)
... assert mymodule.date(2009, 6, 8) == date(2009, 6, 8)
...
답변
나는 이것에 대해 조금 늦게 온 것 같지만 여기서 가장 큰 문제는 datetime.date.today를 직접 패치하고 문서에 따르면 이것이 잘못되었다는 것입니다.
예를 들어 테스트 된 기능이있는 파일로 가져온 참조를 패치해야합니다.
다음과 같은 functions.py 파일이 있다고 가정 해 봅시다.
import datetime
def get_today():
return datetime.date.today()
그런 다음 테스트에서 다음과 같은 것이 있어야합니다
import datetime
import unittest
from functions import get_today
from mock import patch, Mock
class GetTodayTest(unittest.TestCase):
@patch('functions.datetime')
def test_get_today(self, datetime_mock):
datetime_mock.date.today = Mock(return_value=datetime.strptime('Jun 1 2005', '%b %d %Y'))
value = get_today()
# then assert your thing...
이것이 약간 도움이되기를 바랍니다.
답변
에 추가하려면 다니엘 G의 솔루션 :
from datetime import date
class FakeDate(date):
"A manipulable date replacement"
def __new__(cls, *args, **kwargs):
return date.__new__(date, *args, **kwargs)
인스턴스화하면 일반 datetime.date 객체를 반환하지만 변경할 수있는 클래스가 만들어집니다.
@mock.patch('datetime.date', FakeDate)
def test():
from datetime import date
FakeDate.today = classmethod(lambda cls: date(2010, 1, 1))
return date.today()
test() # datetime.date(2010, 1, 1)
답변
나는 며칠 전에 같은 상황에 처해 있었고 내 솔루션은 모듈에서 함수를 정의하여 테스트하고 조롱하는 것이 었습니다.
def get_date_now():
return datetime.datetime.now()
오늘 저는 FreezeGun 에 대해 알아 냈습니다 .이 사건을 아름답게 다루는 것 같습니다.
from freezegun import freeze_time
import datetime
import unittest
@freeze_time("2012-01-14")
def test():
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)
답변
가장 쉬운 방법은 다음과 같습니다.
import datetime
from unittest.mock import Mock, patch
def test():
datetime_mock = Mock(wraps=datetime.datetime)
datetime_mock.now.return_value = datetime.datetime(1999, 1, 1)
with patch('datetime.datetime', new=datetime_mock):
assert datetime.datetime.now() == datetime.datetime(1999, 1, 1)
이 솔루션에 대한주의 : 모든 기능 datetime module
로부터 target_module
중지됩니다 작업.