【问题标题】:Trying to mock patch a function, but getting PIL\\Image.py'> does not have the attribute 'save'尝试模拟修补函数,但获取 PIL\\Image.py'> 没有属性“保存”
【发布时间】:2021-09-30 07:49:58
【问题描述】:

我正在使用 pytest-mock,但是抛出的异常来自 mock.patch 代码,我已经验证如果我使用 @mock.patch 装饰器语法会发生同样的错误。

MRE(确保您已安装 pytest 和 pytest-mock,无需导入任何内容):

def test_image(mocker):
    mocker.patch("PIL.Image.save")

现在在这个模块上运行 pytest。

错误:

E           AttributeError: <module 'PIL.Image' from 'c:\\users\\...\\site-packages\\PIL\\Image.py'> does not have the attribute 'save'

我可以清楚地看到Image.py确实包含一个名为save的函数,但是函数不被视为属性吗?我从来没有听说过这个词用于模块的内容。

【问题讨论】:

    标签: python mocking pytest


    【解决方案1】:

    savePIL.Image.Image class 的实例方法,而不是PIL.Image 模块。

    您应该将补丁实现为:

    def test_image(mocker):
        mocker.patch("PIL.Image.Image.save")
    

    如果您需要断言save 方法在Image 实例上被调用,您需要一个绑定到模拟的name。 您可以通过模拟 Image 类并将 Mock 实例绑定到其 save 方法来实现它。例如,

    def test_image(mocker):
        # prepare
        klass = mocker.patch("PIL.Image.Image")
        instance = klass.return_value
        instance.save = mocker.Mock() 
        
        # act
        # Do operation that invokes save method on `Image` instance
    
        # test
        instance.save.assert_called()
    

    【讨论】:

    • 我完全错过了这是一种方法,而不是一个简单的功能,谢谢。我仍然有点困惑的一件事是我现在如何在断言中引用已修补的方法。 PIL.Image.Image.save.assert_not_called() 似乎有效,但这意味着我必须将 PIL 导入我的测试模块,这似乎有点奇怪,因为我不需要那个导入来修补它。
    • 我已经更新了我的回复,以提供一个示例,说明您如何实现它并让您的测试实现免于不必要的导入。
    • 再次感谢,我实际上能够简化您的示例,只需为mocker.patch("PIL.Image.Image.save") 分配一个名称,然后对其进行断言。这对我有帮助,因为它既短又避免修补整个课程,这会破坏测试的另一部分。
    猜你喜欢
    • 2015-07-31
    • 2015-11-15
    • 2021-04-04
    • 1970-01-01
    • 2021-12-13
    • 2015-05-29
    • 1970-01-01
    • 2021-02-17
    • 2022-07-16
    相关资源
    最近更新 更多