Python:如何模拟datetime.utcnow()?

Python:如何模拟datetime.utcnow()?,python,unit-testing,mocking,Python,Unit Testing,Mocking,我有以下资料: from datetime import datetime def get_report_month_key(): month_for_report = datetime.utcnow() return month_for_report.strftime("%Y%m") 如何模拟datetime.utcnow(),以便在此函数上编写单元测试 尝试阅读此内容,但我无法在utcnow()上使其对我起作用。如果您的代码位于另一个文件中,则需要在导入发生的位置进行修

我有以下资料:

from datetime import datetime

def get_report_month_key():
    month_for_report = datetime.utcnow()
    return month_for_report.strftime("%Y%m") 
如何模拟datetime.utcnow(),以便在此函数上编写单元测试


尝试阅读此内容,但我无法在utcnow()上使其对我起作用。

如果您的代码位于另一个文件中,则需要在导入发生的位置进行修补(让我们调用您的文件file1.py):

当然,我会用unittest framework来包装它。

在您的测试文件中:

from yourfile import get_report_month_key
import mock
import unittest
from datetime import datetime

class TestCase(unittest.TestCase):

    @mock.patch('yourfile.datetime')
    def test_dt(self, mock_dt):
        mock_dt.utcnow = mock.Mock(return_value=datetime(1901, 12, 21))
        r = get_report_month_key()
        self.assertEqual('190112', r)

当修补内置Python模块变得很复杂时(如
datetime
,请参见例如or)也可以使用的方法是将函数包装在自定义模块中,然后可以轻松修补

因此,您不用调用
datetime.datetime.utcnow()
,而是使用如下函数

import datetime


def get_utc_now():
    return datetime.datetime.utcnow()
那么,修补这一个就像

import datetime

# use whatever datetime you need here    
fixed_now = datetime.datetime(2017, 8, 21, 13, 42, 20)
with patch('your_module_name.get_utc_now', return_value=fixed_now):
    # call the code using get_utc_now() here
    pass

使用
补丁
装饰程序而不是上下文管理器也会起到类似的作用。

如果您在测试的模块中没有创建任何
日期时间
实例,dasjotre接受的答案也会起作用。如果尝试创建
datetime
它将创建一个模拟对象,而不是在标准
datetime
对象上使用预期方法创建的对象。这是因为它用mock替换了整个类定义。您可以使用类似的方法,通过使用
datetime
作为基础来创建模拟定义,而不是这样做

mymodule.py

from datetime import datetime

def after_y2k():
    y2k = datetime(2000, 1, 1)
    return y2k < datetime.utcnow()
import unittest
import datetime
from mock import patch, Mock
import mymodule
from mymodule import after_y2k


class ModuleTests(unittest.TestCase):
    @patch.object(mymodule, 'datetime', Mock(wraps=datetime.datetime))
    def test_after_y2k_passes(self):
        # Mock the return and run your test (Note you are doing it on your module)
        mymodule.datetime.utcnow.return_value = datetime.datetime(2002, 01, 01)
        self.assertEqual(True, after_y2k())

        mymodule.datetime.utcnow.return_value = datetime.datetime(1999, 01, 01)
        self.assertEqual(False, after_y2k())

    @patch('mymodule.datetime')
    def test_after_y2k_fails(self, mock_dt):
        # Run your tests
        mock_dt.utcnow = Mock(return_value=datetime.datetime(2002, 01, 01))
        self.assertEqual(True, after_y2k())

        # FAILS!!! because the object returned by utcnow is a MagicMock w/o 
        # datetime methods like "__lt__"
        mock_dt.utcnow = Mock(return_value=datetime.datetime(1999, 01, 01))
        self.assertEqual(False, after_y2k())

您可以尝试使用冻结时间模块

from yourfile import get_report_month_key
from freezegun import freeze_time
import unittest

class TestCase(unittest.TestCase):

    @freeze_time('2017-05-01')
    def get_report_month_key_test():
       get_report_month_key().should.equal('201705')

@当我尝试上述方法时,我得到了ImportError:没有名为get\u report\u month\u key的模块,我的函数确实在say file1.py中。这对我来说失败了,因为
TypeError:无法设置内置/扩展类型“datetime.datetime”的属性。
。这里的进一步解释是:你不能修补内置的属性。如果我们只是想在一个文件中模拟它,那么这是迄今为止我读过的最好和最简单的想法!谢谢在我尝试的四个答案中,只有这一个有效。谢谢使用pytest和Python3.7时,这种方法最适合我
from yourfile import get_report_month_key
from freezegun import freeze_time
import unittest

class TestCase(unittest.TestCase):

    @freeze_time('2017-05-01')
    def get_report_month_key_test():
       get_report_month_key().should.equal('201705')