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

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

也许有人能提出一个更好的办法?


当前回答

对我来说,最好的方法是结合@Daniel G和@frx08的解决方案:

class Test_mock_date:
    class NewDate(datetime.datetime):
        @classmethod
        def now(cls, tz=None):
            return cls(2021, 5, 12)

    def test_mock_date(self):
        with patch('datetime.datetime', new = self.NewDate):
            assert datetime.datetime.now() == datetime.datetime(2021, 5, 12, 0, 0)

你可以看看下面我写的关于如何使用MagicMock的不同示例的中型文章https://medium.com/@camposer/d2113513b365

其他回答

下面是另一种模拟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模块。

对我来说,最好的方法是结合@Daniel G和@frx08的解决方案:

class Test_mock_date:
    class NewDate(datetime.datetime):
        @classmethod
        def now(cls, tz=None):
            return cls(2021, 5, 12)

    def test_mock_date(self):
        with patch('datetime.datetime', new = self.NewDate):
            assert datetime.datetime.now() == datetime.datetime(2021, 5, 12, 0, 0)

你可以看看下面我写的关于如何使用MagicMock的不同示例的中型文章https://medium.com/@camposer/d2113513b365

对我来说最简单的方法是:

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模块中的所有功能都将停止工作。

我们可以使用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.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...

希望这能对你有所帮助。