datetime.date.today ()를 조롱하려고 시도했지만 작동하지 않습니다.
왜 이것이 작동하지 않는지 말해 줄 수 있습니까?
>>> 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)
Daniel G 솔루션을 기반으로 다음 접근 방식을 사용할 수 있습니다. 이것은로 타입 검사를 중단하지 않는 이점이 isinstance(d, datetime.date)
있습니다.
import mock
def fixed_today(today):
from datetime import date
class FakeDateType(type):
def __instancecheck__(self, instance):
return isinstance(instance, date)
class FakeDate(date):
__metaclass__ = FakeDateType
def __new__(cls, *args, **kwargs):
return date.__new__(date, *args, **kwargs)
@staticmethod
def today():
return today
return mock.patch("datetime.date", FakeDate)
기본적으로 C 기반 datetime.date
클래스를 자체 Python 하위 클래스로 바꾸면 원래 datetime.date
인스턴스 를 생성 하고 isinstance()
쿼리를 정확히 native로 응답합니다 datetime.date
.
테스트에서 컨텍스트 관리자로 사용하십시오.
with fixed_today(datetime.date(2013, 11, 22)):
# run the code under test
# note, that these type checks will not break when patch is active:
assert isinstance(datetime.date.today(), datetime.date)
datetime.datetime.now()
기능 을 조롱하기 위해 비슷한 접근법을 사용할 수 있습니다 .
나는 며칠 전에 같은 상황에 처해 있었고 내 솔루션은 모듈에서 함수를 정의하여 테스트하고 조롱하는 것이 었습니다.
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)
가장 쉬운 방법은 다음과 같습니다.
from unittest import patch, Mock
def test():
datetime_mock = Mock(wraps=datetime)
datetime_mock.now = Mock(return_value=datetime(1999, 1, 1)
patch('target_module.datetime', new=datetime_mock).start()
이 솔루션에 대한주의 : 모든 기능 datetime module
로부터 target_module
중지됩니다 작업.
일반적으로, 어딘가에 모듈로 가져 왔 datetime
거나 아마도 datetime.date
가져 왔습니다. 메소드를 모의하는보다 효과적인 방법은 메소드를 가져 오는 모듈에 패치하는 것입니다. 예:
a.py
from datetime import date
def my_method():
return date.today()
그런 다음 테스트를 위해 모의 객체 자체가 테스트 메소드의 인수로 전달됩니다. 원하는 결과 값으로 모의를 설정 한 다음 테스트중인 메소드를 호출하십시오. 그런 다음 메소드가 원하는 것을 수행했다고 주장합니다.
>>> import mock
>>> import a
>>> @mock.patch('a.date')
... def test_my_method(date_mock):
... date_mock.today.return_value = mock.sentinel.today
... result = a.my_method()
... print result
... date_mock.today.assert_called_once_with()
... assert mock.sentinel.today == result
...
>>> test_my_method()
sentinel.today
A word of warning. It is most certainly possible to go overboard with mocking. When you do, it makes your tests longer, harder to understand, and impossible to maintain. Before you mock a method as simple as datetime.date.today
, ask yourself if you really need to mock it. If your test is short and to the point and works fine without mocking the function, you may just be looking at an internal detail of the code you're testing rather than an object you need to mock.
Several solutions are discussed in http://blog.xelnor.net/python-mocking-datetime/. In summary:
Mock object - Simple and efficient but breaks isinstance() checks:
target = datetime.datetime(2009, 1, 1)
with mock.patch.object(datetime, 'datetime', mock.Mock(wraps=datetime.datetime)) as patched:
patched.now.return_value = target
print(datetime.datetime.now())
Mock class
import datetime
import mock
real_datetime_class = datetime.datetime
def mock_datetime_now(target, dt):
class DatetimeSubclassMeta(type):
@classmethod
def __instancecheck__(mcs, obj):
return isinstance(obj, real_datetime_class)
class BaseMockedDatetime(real_datetime_class):
@classmethod
def now(cls, tz=None):
return target.replace(tzinfo=tz)
@classmethod
def utcnow(cls):
return target
# Python2 & Python3 compatible metaclass
MockedDatetime = DatetimeSubclassMeta('datetime', (BaseMockedDatetime,), {})
return mock.patch.object(dt, 'datetime', MockedDatetime)
Use as:
with mock_datetime_now(target, datetime):
....
Maybe you could use your own "today()" method that you will patch where needed. Example with mocking utcnow() can be found here: https://bitbucket.org/k_bx/blog/src/tip/source/en_posts/2012-07-13-double-call-hack.rst?at=default
I implemented @user3016183 method using a custom decorator:
def changeNow(func, newNow = datetime(2015, 11, 23, 12, 00, 00)):
"""decorator used to change datetime.datetime.now() in the tested function."""
def retfunc(self):
with mock.patch('mymodule.datetime') as mock_date:
mock_date.now.return_value = newNow
mock_date.side_effect = lambda *args, **kw: datetime(*args, **kw)
func(self)
return retfunc
I thought that might help someone one day...
It's possible to mock functions from datetime
module without adding side_effects
import mock
from datetime import datetime
from where_datetime_used import do
initial_date = datetime.strptime('2018-09-27', "%Y-%m-%d")
with mock.patch('where_datetime_used.datetime') as mocked_dt:
mocked_dt.now.return_value = initial_date
do()
Here's another way to mock datetime.date.today()
with an added bonus that the rest of datetime
functions continue to work, as the mock object is configured to wrap the original datetime
module:
from unittest import mock, TestCase
import foo_module
class FooTest(TestCase):
@mock.patch(f'{foo_module.__name__}.datetime', wraps=datetime)
def test_something(self, mock_datetime):
# mock only datetime.date.today()
mock_datetime.date.today.return_value = datetime.date(2019, 3, 15)
# other calls to datetime functions will be forwarded to original datetime
Note the wraps=datetime
argument to mock.patch()
– when the foo_module
uses other datetime
functions besides date.today()
they will be forwarded to the original wrapped datetime
module.
For those of you using pytest with mocker here is how I mocked datetime.datetime.now()
which is very similar to the original question.
test_get_now(mocker):
datetime_mock = mocker.patch("blackline_accounts_import.datetime",)
datetime_mock.datetime.now.return_value=datetime.datetime(2019,3,11,6,2,0,0)
now == function_being_tested() # run function
assert now == datetime.datetime(2019,3,11,6,2,0,0)
Essentially the mock has to be set to return the specified date. You aren't able to patch over datetime's object directly.
I made this work by importing datetime
as realdatetime
and replacing the methods I needed in the mock with the real methods:
import datetime as realdatetime
@mock.patch('datetime')
def test_method(self, mock_datetime):
mock_datetime.today = realdatetime.today
mock_datetime.now.return_value = realdatetime.datetime(2019, 8, 23, 14, 34, 8, 0)
You can mock datetime
using this:
In the module sources.py
:
import datetime
class ShowTime:
def current_date():
return datetime.date.today().strftime('%Y-%m-%d')
In your tests.py
:
from unittest import TestCase, mock
import datetime
class TestShowTime(TestCase):
def setUp(self) -> None:
self.st = sources.ShowTime()
super().setUp()
@mock.patch('sources.datetime.date')
def test_current_date(self, date_mock):
date_mock.today.return_value = datetime.datetime(year=2019, month=10, day=1)
current_date = self.st.current_date()
self.assertEqual(current_date, '2019-10-01')
참고URL : https://stackoverflow.com/questions/4481954/trying-to-mock-datetime-date-today-but-not-working
'Programing' 카테고리의 다른 글
PHP를 사용하여 디렉토리의 전체 내용을 다른 디렉토리로 복사 (0) | 2020.06.27 |
---|---|
이진 검색 복잡성을 계산하는 방법 (0) | 2020.06.27 |
모든 저장 프로 시저에 실행 실행 (0) | 2020.06.26 |
node.js에서 process.env.PORT의 값을 변경하는 방법은 무엇입니까? (0) | 2020.06.26 |
파이썬에서 고유 ID를 어떻게 생성 할 수 있습니까? (0) | 2020.06.26 |