谁能告诉我为什么这行不通?

>>> 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.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...

希望这能对你有所帮助。

其他回答

值得注意的是,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)
...

几天前我遇到了同样的情况,我的解决方案是在模块中定义一个函数来测试和模拟:

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)

注意:target_module中的datetime模块中的所有功能都将停止工作。

您可以使用以下基于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。日期实例,并响应isinstance()查询完全与本机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()函数。

我想我来晚了一点,但我认为这里的主要问题是您直接修补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...

希望这能对你有所帮助。