【问题标题】:How do I mock a method on an object created by an @patch decorator?如何模拟由@patch 装饰器创建的对象的方法?
【发布时间】:2019-06-11 18:49:19
【问题描述】:

我正在尝试使用 @patch 装饰器和模拟对象来测试我的代码消耗一些库的行为。不幸的是,我看不到任何方法可以只使用装饰器来做我想做的事情,而且似乎我应该能够做到。我意识到通常我应该更关心方法的返回值,而不是它对库的特定调用序列,但是编写一个测试来比较一个图像和另一个图像是非常困难的。

我想也许我可以创建我的模拟对象的实例,然后使用@patch.object(...),但这不起作用,显然@patch('MockObject.method') 只会模拟类方法。我可以使用with patch.object(someMock.return_value, 'method') as mockName 使代码正常工作,但这会使我的测试变得混乱。

from some.module import SomeClass


class MockObject:
    def method(self):
        pass


class TestClass:
    @patch('SomeClass.open', return_value=MockObject())
    @patch('??????.method')  # I can't find any value to put here that works
    def test_as_desired(self, mockMethod, mockOpen):
        instance = SomeClass.open()
        instance.method()

        mockOpen.assert_called_once()
        mockMethod.assert_called_once()

    @patch('SomeClass.open', return_value=MockObject())
    def test_messy(self, mockOpen):
        with patch.object(mockOpen.return_value, 'method') as mockMethod:
            instance = SomeClass.open()
            instance.method()

            mockOpen.assert_called_once()
            mockMethod.assert_called_once()

【问题讨论】:

  • 补丁是用来修改创建超出你控制范围的对象; MockObject 的实例并非如此。
  • 我要修补 MockObject.method 的原因是为了验证该方法确实被调用(以及我期望的参数,为了简单起见,我在这个例子中省略了)
  • 所以在实例化的时候配置它;不要试图在事后修补它。
  • 我将它实例化为另一个@patch 的返回值。再说一次,我想@patch模拟对象上的方法的原因是我可以将它注入测试函数并确保它被正确调用。
  • 感谢 cmets 和建议。不过,我尝试做我想做的事情是有原因的。

标签: python unit-testing mocking pytest


【解决方案1】:

我认为你把事情复杂化了:

import unittest.mock

@unittest.mock.patch.object(SomeClass, open=mock.Mock())
def test_as_desired(self, mock_open):
    instance = SomeClass.open()  # SomeClass.open is a mock, so its return value is too
    instance.method()

    mock_ppen.assert_called_once()
    instance.method.assert_called_once()

【讨论】:

  • 这很有意义。不幸的是,您的示例代码在 pytest 中不起作用,因为 @patch.object 调用似乎无法理解 kwargs 您使用它们的方式。我替换了@patch.object(SomeClass, 'open', return_value=Mock()),但随后断言instance.method.assert_called_once() 失败
  • 其实我说的并不完全正确:一旦我更正了@patch的调用,我就可以断言mock_open.return_value.method.assert_called_once
猜你喜欢
  • 2018-10-08
  • 1970-01-01
  • 2018-12-04
  • 2019-08-31
  • 1970-01-01
  • 2013-07-19
  • 2022-01-12
  • 2014-12-06
  • 1970-01-01
相关资源
最近更新 更多