如何在保留其他方法的同时修补 datetime 的 now 方法?
How to patch the now method of datetime while preserving other methods?
是我要测试的功能
from datetime import datetime, timedelta, time
def my_func():
result_date = datetime.combine(datetime.now(), time.min) + timedelta(days=look_forward)
...
这是我的单元测试代码
@patch('batch.mymodule.datetime')
def test_retrieve_data(self, mock_datetime):
mock_datetime.now = Mock(return_value=datetime.datetime.strptime('Feb 14 2015', '%b %d %Y'))
my_func
我认为它按预期工作。然而 patch
也嘲笑了另一个方法 combine
。稍后我会从 my_func
得到这个异常
BadValueError: Expected datetime, got <MagicMock name='datetime.combine().__add__()' id='4494328976'>
我可以通过将此添加到单元测试来修复它:
mock_datetime.combine = datetime.datetime.combine
但这意味着我必须在 datetime
中修补每个单独的方法,如果它被使用的话。
有没有更好、更简单的选择?
定义 datetime.datetime
subclass 以将其用作模拟对象的 class:
class MockDatetime(datetime.datetime):
fake_now = None
@classmethod
def now(cls):
return cls.fake_now
class TestFoo(unittest.TestCase):
@patch('mod.datetime', MockDatetime)
def test_retrieve_data(self):
MockDatetime.fake_now = datetime.datetime(2015, 2, 14)
my_func()
这并没有回答您的问题,但我认为值得一提的是另一种方法。对于我的项目,我使用了 freezegun。
from freezegun import freeze_time
import datetime
class SomeTest(TestCase):
@freeze_time("2015-08-10 00:00:00")
def some_test_case(self):
print(datetime.now())
2015-08-10 00:00:00
是我要测试的功能
from datetime import datetime, timedelta, time
def my_func():
result_date = datetime.combine(datetime.now(), time.min) + timedelta(days=look_forward)
...
这是我的单元测试代码
@patch('batch.mymodule.datetime')
def test_retrieve_data(self, mock_datetime):
mock_datetime.now = Mock(return_value=datetime.datetime.strptime('Feb 14 2015', '%b %d %Y'))
my_func
我认为它按预期工作。然而 patch
也嘲笑了另一个方法 combine
。稍后我会从 my_func
得到这个异常
BadValueError: Expected datetime, got <MagicMock name='datetime.combine().__add__()' id='4494328976'>
我可以通过将此添加到单元测试来修复它:
mock_datetime.combine = datetime.datetime.combine
但这意味着我必须在 datetime
中修补每个单独的方法,如果它被使用的话。
有没有更好、更简单的选择?
定义 datetime.datetime
subclass 以将其用作模拟对象的 class:
class MockDatetime(datetime.datetime):
fake_now = None
@classmethod
def now(cls):
return cls.fake_now
class TestFoo(unittest.TestCase):
@patch('mod.datetime', MockDatetime)
def test_retrieve_data(self):
MockDatetime.fake_now = datetime.datetime(2015, 2, 14)
my_func()
这并没有回答您的问题,但我认为值得一提的是另一种方法。对于我的项目,我使用了 freezegun。
from freezegun import freeze_time
import datetime
class SomeTest(TestCase):
@freeze_time("2015-08-10 00:00:00")
def some_test_case(self):
print(datetime.now())
2015-08-10 00:00:00