Python 为“mock.patch”制作包装`

Python 为“mock.patch”制作包装`,python,testing,mocking,python-mock,Python,Testing,Mocking,Python Mock,来自mock.patch的一些定制补丁我想反复使用,而不要把我的测试代码和补丁设置的拷贝粘贴在一起。e、 g.,它被改编成datetime,将在我的代码中填充 with patch('mymodule.datetime') as mock_datetime: mock_datetime.datetime.utcnow.return_value = datetime.datetime(2010, 10, 8, 9, 10) mock_date.datetime.side_effec

来自
mock.patch的一些定制补丁
我想反复使用,而不要把我的测试代码和补丁设置的拷贝粘贴在一起。e、 g.,它被改编成datetime,将在我的代码中填充

with patch('mymodule.datetime') as mock_datetime:
    mock_datetime.datetime.utcnow.return_value = datetime.datetime(2010, 10, 8, 9, 10)
    mock_date.datetime.side_effect = lambda *args, **kw: datetime.datetime(*args, **kw)

如何将此功能包装到一个单行调用中?

下面是一个资源管理器类,它将为您完成这项工作。由于您可能希望将其与测试类放在一个单独的文件中,因此它使用
inspect
查找调用模块,以便将正确限定的目标模块名称传递给
mock.patch

import datetime
import inspect
# import mock according to your python version

class mock_datetime(object):

    def __init__(self, target, new_utcnow):
        self.new_utcnow = new_utcnow
        self.target = target

    def __enter__(self):
        calling_module = inspect.getmodule(inspect.stack()[1][0])
        target_from_here = calling_module.__name__ + '.' + self.target
        self.patcher = mock.patch(target_from_here)
        mock_dt = self.patcher.start()
        mock_dt.datetime.utcnow.return_value = self.new_utcnow.replace(tzinfo=None)
        mock_dt.datetime.side_effect = lambda *args, **kw: datetime.datetime(*args, **kw)
        return mock_dt

    def __exit__(self, *args, **kwargs):
        self.patcher.stop()
然后,您可以使用

with mock_datetime('mymodule.datetime', datetime.datetime(2016, 3, 23)):
    assert mymodule.datetime.datetime.utcnow() == datetime.datetime(2016, 3, 23)

下面是一个资源管理器类,它将为您实现这一点。由于您可能希望将其与测试类放在一个单独的文件中,因此它使用
inspect
查找调用模块,以便将正确限定的目标模块名称传递给
mock.patch

import datetime
import inspect
# import mock according to your python version

class mock_datetime(object):

    def __init__(self, target, new_utcnow):
        self.new_utcnow = new_utcnow
        self.target = target

    def __enter__(self):
        calling_module = inspect.getmodule(inspect.stack()[1][0])
        target_from_here = calling_module.__name__ + '.' + self.target
        self.patcher = mock.patch(target_from_here)
        mock_dt = self.patcher.start()
        mock_dt.datetime.utcnow.return_value = self.new_utcnow.replace(tzinfo=None)
        mock_dt.datetime.side_effect = lambda *args, **kw: datetime.datetime(*args, **kw)
        return mock_dt

    def __exit__(self, *args, **kwargs):
        self.patcher.stop()
然后,您可以使用

with mock_datetime('mymodule.datetime', datetime.datetime(2016, 3, 23)):
    assert mymodule.datetime.datetime.utcnow() == datetime.datetime(2016, 3, 23)

@brandones的解决方案非常好!但我发现,如果不进行检查,使用起来会更容易,如下所示:

#testhelpers.py
将unittest.mock导入为mock
导入日期时间
类MockDatetime():
定义初始(自我、目标、utcnow):
self.utcnow=utcnow
self.target=目标
定义输入(自我):
self.patcher=mock.patch(self.target)
mock_dt=self.patcher.start()
mock_dt.datetime.utcnow.return_value=self.utcnow.replace(tzinfo=None)
mock_dt.datetime.side_effect=lambda*args,**kw:datetime.datetime(*args,**kw)
返回模拟值
定义退出(自我,*args,**kwargs):
self.patcher.stop()
#testhelpers\u test.py
导入日期时间
从testhelpers导入MockDatetime
def test_umock_datetime():
使用MockDatetime('testhelpers\u test.datetime',datetime.datetime(2019,4,29,9,10,23,1234)):
断言datetime.datetime.utcnow()==datetime.datetime(2019,4,29,9,10,23,1234)

由@brandones提供的解决方案非常出色!但我发现,如果不进行检查,使用起来会更容易,如下所示:

#testhelpers.py
将unittest.mock导入为mock
导入日期时间
类MockDatetime():
定义初始(自我、目标、utcnow):
self.utcnow=utcnow
self.target=目标
定义输入(自我):
self.patcher=mock.patch(self.target)
mock_dt=self.patcher.start()
mock_dt.datetime.utcnow.return_value=self.utcnow.replace(tzinfo=None)
mock_dt.datetime.side_effect=lambda*args,**kw:datetime.datetime(*args,**kw)
返回模拟值
定义退出(自我,*args,**kwargs):
self.patcher.stop()
#testhelpers\u test.py
导入日期时间
从testhelpers导入MockDatetime
def test_umock_datetime():
使用MockDatetime('testhelpers\u test.datetime',datetime.datetime(2019,4,29,9,10,23,1234)):
断言datetime.datetime.utcnow()==datetime.datetime(2019,4,29,9,10,23,1234)