Ste*_*ong 12 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")
Run Code Online (Sandbox Code Playgroud)
如何模拟datetime.utcnow()以便我可以在此函数上编写单元测试?
试着读这一个,但我无法得到它的工作对我来说在utcnow()
小智 25
在您的测试文件中:
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)
Run Code Online (Sandbox Code Playgroud)
Dir*_*irk 11
当修补内置 Python 模块变得很复杂时,什么也有效(就像使用datetime,参见例如https://solidgeargroup.com/mocking-the-time或https://nedbatchelder.com/blog/201209/mocking_datetimetoday .html或https://gist.github.com/rbarrois/5430921)正在将函数包装在自定义函数中,然后可以轻松修补。
因此,datetime.datetime.utcnow()您可以使用类似的函数,而不是调用
import datetime
def get_utc_now():
return datetime.datetime.utcnow()
Run Code Online (Sandbox Code Playgroud)
然后,修补这个很简单
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
Run Code Online (Sandbox Code Playgroud)
使用patch装饰器而不是上下文管理器的工作方式类似。
如果未datetime在要测试的模块中创建任何实例,则dasjotre接受的答案有效。如果尝试创建一个datetime对象,它将创建一个Mock对象,而不是在标准datetime对象上使用预期方法的对象。这是因为它用模拟代替了整个类的定义。代替执行此操作,您可以使用类似的方法通过将其datetime用作基础来创建模拟定义。
mymodule.py
from datetime import datetime
def after_y2k():
y2k = datetime(2000, 1, 1)
return y2k < datetime.utcnow()
Run Code Online (Sandbox Code Playgroud)
test_mymodule.py
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())
Run Code Online (Sandbox Code Playgroud)
小智 5
您可以尝试使用 freezetime 模块。
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')
Run Code Online (Sandbox Code Playgroud)