如何在@patch装饰器创建的对象上模拟方法?

时间:2019-06-11 18:49:19

标签: python unit-testing mocking pytest

我正在尝试使用@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()

1 个答案:

答案 0 :(得分: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()