Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 从_getattr__方法检索的模拟函数_Python_Python 3.x_Unit Testing_Mocking_Pytest - Fatal编程技术网

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”
:/with
patch.object
,但由于您的评论,我尝试手动将模拟分配给Git.pull,它成功了。谢谢。你必须通过
create=True
才能获得补丁方法来替换不存在的属性。@jornsharpe哇:D这是一个非常简单的解决方案,它工作得非常好。我可以使用
patch.object
而不是脏的解决方案,这太好了。您可以添加它作为答案,这样我就可以接受它(: