Python 从_getattr__方法检索的模拟函数
我正在自动化一些存储库操作,并将其用于此工作。让我们简化一下,假设我想断言我的函数是否在存储库中调用了Python 从_getattr__方法检索的模拟函数,python,python-3.x,unit-testing,mocking,pytest,Python,Python 3.x,Unit Testing,Mocking,Pytest,我正在自动化一些存储库操作,并将其用于此工作。让我们简化一下,假设我想断言我的函数是否在存储库中调用了pull方法。代码如下: from pytest_mock import MockFixture from git import Git, Repo repo = Repo('/Users/Jatimir/path/to/repo') def pull() -> None: repo.git.pull() 然而,我注意到,Git类有些特殊,没有实现pull。相反,它将所有通信
pull
方法。代码如下:
from pytest_mock import MockFixture
from git import Git, Repo
repo = Repo('/Users/Jatimir/path/to/repo')
def pull() -> None:
repo.git.pull()
然而,我注意到,Git
类有些特殊,没有实现pull
。相反,它将所有通信“委托”给\uuuu getattr\uuuu
,后者使用另一种方法来完成此任务
def __getattr__(self, name):
...
return lambda *args, **kwargs: self._call_process(name, *args, **kwargs)
我的问题是如何进行测试?我正在使用with,它提供了一个mocker
装置,以下是我的尝试:
def test_pull1(mocker: MockFixture) -> None:
pull_mock = mocker.MagicMock(name='pull')
getattr_mock = mocker.MagicMock(name='__getattr__', return_value=pull_mock)
mocker.patch.object(Git, '__getattr__', getattr_mock)
pull()
pull_mock.assert_called_once_with()
def test_pull2(mocker: MockFixture) -> None:
pull_mock = mocker.Mock(name='pull')
def __getattr__(self, name):
if name == 'pull':
return pull_mock
mocker.patch.object(Git, '__getattr__', __getattr__)
pull()
pull_mock.assert_called_once_with()
它们都能工作,但我觉得有更好的方法,也许我的测试方法是错误的。多亏了指导我使用create
参数,我用以下代码实现了我想要的:
def test_pull(mocker: MockFixture) -> None:
m = mocker.patch.object(Git, 'pull', create=True)
pull()
m.assert_called_once_with()
摘录自解释create=True
的功能:
默认情况下,patch()将无法替换不存在的属性。如果传入create=True,而该属性不存在,则在调用修补函数时,修补程序将为您创建该属性,然后再次删除该属性
Git
使用\uu getattr\uuu
这一事实是一个实现细节;只要模仿pull
方法,就像他们以正常方式实现它一样。@jornsharpe这是我尝试的第一件事,我得到了AttributeError:没有属性“pull”
:/withpatch.object
,但由于您的评论,我尝试手动将模拟分配给Git.pull,它成功了。谢谢。你必须通过create=True
才能获得补丁方法来替换不存在的属性。@jornsharpe哇:D这是一个非常简单的解决方案,它工作得非常好。我可以使用patch.object
而不是脏的解决方案,这太好了。您可以添加它作为答案,这样我就可以接受它(: