【问题标题】:Mocking functions retrieved from __getattr__ method从 __getattr__ 方法检索的模拟函数
【发布时间】:2018-12-01 13:59:11
【问题描述】:

我正在自动化一些存储库操作,我正在使用GitPython 来完成这项工作。让我们简化一些事情并假设我想断言我的函数是否在存储库上调用了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。相反,它将所有流量“委托”给__getattr__,后者使用另一种方法来完成这项工作。

def __getattr__(self, name):
    ...
    return lambda *args, **kwargs: self._call_process(name, *args, **kwargs)

我的问题是如何进行测试?我正在使用pytest 和pytest-mock,它提供了一个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()

它们都有效,但我觉得有更好的方法,也许我的测试方法是错误的。

【问题讨论】:

  • Git 使用__getattr__ 是一个实现细节;只需模拟 pull 方法,就好像他们以正常方式实现它一样。
  • @jonrsharpe 这是我尝试的第一件事,我得到了AttributeError: <class 'git.cmd.Git'> does not have the attribute 'pull' :/ 和patch.object,但是感谢您的评论,我尝试手动为 Git.pull 分配一个 Mock 并且它起作用了。谢谢。
  • 你必须通过create=True来获取补丁方法来替换不存在的属性。
  • @jonrsharpe 哇:D 这是一个如此简单的解决方案,它完美地工作。很高兴我可以使用patch.object 而不是我肮脏的解决方案。您可以将其添加为答案,因此我可以接受(:

标签: python python-3.x unit-testing mocking pytest


【解决方案1】:

感谢jonrsharpe 指导我使用create 参数,我设法通过以下代码实现了我想要的:

def test_pull(mocker: MockFixture) -> None:
    m = mocker.patch.object(Git, 'pull', create=True)
    pull()
    m.assert_called_once_with()

摘自 documentation 解释 create=True 的作用:

默认情况下,patch() 将无法替换不存在的属性。如果传入create=True,属性不存在,patch会在调用patched函数时为你创建属性,之后再删除。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-10
    • 1970-01-01
    • 1970-01-01
    • 2011-06-20
    • 2018-07-24
    相关资源
    最近更新 更多