谁能告诉我为什么这行不通?
>>> 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)
也许有人能提出一个更好的办法?
当前回答
一般来说,你会有datetime或datetime。将日期导入某个模块。模拟该方法的一种更有效的方法是在导入它的模块上修补它。例子:
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
警告一句。很有可能嘲讽得过火了。当您这样做时,它会使您的测试更长、更难理解,并且不可能维护。在模拟像datetime.date这样简单的方法之前。今天,问问自己是否真的需要嘲笑它。如果您的测试短小精干,并且在不模拟函数的情况下运行良好,那么您可能只看到了正在测试的代码的内部细节,而不是需要模拟的对象。
其他回答
在Daniel G的解决方案中补充一点:
from datetime import date
class FakeDate(date):
"A manipulable date replacement"
def __new__(cls, *args, **kwargs):
return date.__new__(date, *args, **kwargs)
这将创建一个类,当实例化时,该类将返回一个正常的datetime。对象,但也可以更改。
@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)
一般来说,你会有datetime或datetime。将日期导入某个模块。模拟该方法的一种更有效的方法是在导入它的模块上修补它。例子:
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
警告一句。很有可能嘲讽得过火了。当您这样做时,它会使您的测试更长、更难理解,并且不可能维护。在模拟像datetime.date这样简单的方法之前。今天,问问自己是否真的需要嘲笑它。如果您的测试短小精干,并且在不模拟函数的情况下运行良好,那么您可能只看到了正在测试的代码的内部细节,而不是需要模拟的对象。
我通过将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()的方法,其额外的好处是其余的datetime函数继续工作,因为模拟对象被配置为包装原始的datetime模块:
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
注意mock.patch()的wraps=datetime参数——当foo_module使用date.today()之外的其他datetime函数时,它们将被转发到原始包装的datetime模块。
对我来说最简单的方法是:
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)
注意:target_module中的datetime模块中的所有功能都将停止工作。