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