谁能告诉我为什么这行不通?
>>> 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)
也许有人能提出一个更好的办法?
谁能告诉我为什么这行不通?
>>> 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)
也许有人能提出一个更好的办法?
当前回答
我们可以使用pytest-mock (https://pypi.org/project/pytest-mock/)模拟器对象来模拟特定模块中的日期时间行为
假设您想在以下文件中模拟日期时间
# File path - source_dir/x/a.py
import datetime
def name_function():
name = datetime.now()
return f"name_{name}"
在测试函数中,mock将在测试运行时添加到函数中
def test_name_function(mocker):
mocker.patch('x.a.datetime')
x.a.datetime.now.return_value = datetime(2019, 1, 1)
actual = name_function()
assert actual == "name_2019-01-01"
其他回答
我通过将datetime导入为realdatetime并将我在模拟中需要的方法替换为实际方法来完成这项工作:
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)
我想我来晚了一点,但我认为这里的主要问题是您直接修补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...
希望这能对你有所帮助。
也许您可以使用自己的“today()”方法,在需要的地方打补丁。使用utcnow()的示例可以在这里找到:https://bitbucket.org/k_bx/blog/src/tip/source/en_posts/2012-07-13-double-call-hack.rst?at=default
monkeypatch的最小工作示例
这个解决方案使用https://pypi.org/project/pytest-mock/包中的monkeypatch。
特点:
仅模拟datetime.today(),但datetime.now()仍然可以正常工作 仅在特定范围内模拟(即块)
import sys
from datetime import datetime
MOCKED_DATETIME_TODAY = datetime(1900, 1, 1, 0, 0, 0)
class MockedDatetime(datetime):
@classmethod
def today(cls):
return MOCKED_DATETIME_TODAY
def test_mock_datetime_today(monkeypatch):
"""Only datetime.today() is mocked and returns some date in 1900. datetime.now() returns still the current date."""
with monkeypatch.context() as mpc:
mpc.setattr(sys.modules[__name__], 'datetime', MockedDatetime)
assert datetime.today() == MOCKED_DATETIME_TODAY # datetime.today() mocked
assert datetime.now() > MOCKED_DATETIME_TODAY # datetime.now() not mocked
assert datetime.today() > MOCKED_DATETIME_TODAY # not mocked anymore
对于那些在测试类中使用补丁程序的人,下面是我如何成功地修补datetime功能:
from datetime import datetime
import unittest
from unittest.mock import Mock, patch
# Replace with the proper path to the module you would
# like datetime to be mocked
from path.to.my_module
class MyTestCases(unittest.TestCase):
def setUp(self):
"""execute on class instantiation"""
# Record both times at the same moment
self.dt_now, self.dt_utcnow = datetime.now(), datetime.utcnow()
# After retrieving real (or hardcoded datetime values),
# proceed to mock them in desired module
self.patch_datetime_functions()
def patch_datetime_functions(self) -> None:
"""
Patch datetime.now() and datetime.utcnow() to prevent issues when
comparing expected dates
"""
# Create a patcher
self.patcher_dt = patch(
'path.to.my_module'
)
# Start but make sure cleanup always occurs
self.patcher_dt.start()
self.addCleanup(self.patcher_dt.stop)
# Perform the actual patch – use lambdas as mock functions
datetime_mock = Mock(wraps=datetime)
datetime_mock.now.return_value = self.dt_now
datetime_mock.utcnow.return_value = self.dt_utcnow
my_module.datetime = datetime_mock
# Here's what it will look like when testing:
def some_test(self):
curr_dt = self.dt_now
returned_dt = my_module.datetime.utcnow()
# Compare the dates
self.assertEqual(curr_dt, returned_dt,
'Datetime values should be equal'
)