测试模拟实例,同时保留其方法可执行

Test mocked instance while leaving its methods executable

我有一些类似于下面的代码,我想使用 pytest_mockClassToTest 中测试一些流程。为此,我需要向它传递一个实现某些特定方法的对象,在本例中为 method1MockClass 中的 method2。在使用 run() 执行 ClassToTest 实例后,我想检查 mock_class 中的某些方法是否被调用,而这些方法必须保持可执行。有什么方法可以做到这一点?

import ClassToTest


class MockClass:
    def method1(self):
        return "method1 output"
    
    def method2(self):
        return "method2 output"


def test_class_to_test():
    mock_class = MockClass()
    class_to_test = ClassToTest(mock_class)
    class_to_test.run()
    
    mock_class.method1.assert_called()
    mock_class.method2.assert_not_called()

如果您只想模拟这些方法的输出,最简单的方法就是使用 MagicMock 并在那里进行修补:

def test_class_to_test(mocker):
    mock_class = mocker.MagicMock()
    mock_class.method1.return_value = "method1 output"
    mock_class.method2.return_value = "method2 output"
    class_to_test = ClassToTest(mock_class)
    class_to_test.run()

    mock_class.method1.assert_called()
    mock_class.method2.assert_not_called()

(在这里使用 mocker,因为你似乎使用 pytest-mock

这样你就不需要单独的 class 来模拟了。
您还可以将模拟移动到一个单独的夹具中:

@pytest.fixture
def mock_class(mocker):
    mock_class = mocker.MagicMock()
    mock_class.method1.return_value = "method1 output"
    mock_class.method2.return_value = "method2 output"
    yield mock_class


def test_class_to_test(mock_class):
    class_to_test = ClassToTest(mock_class)
    class_to_test.run()

    mock_class.method1.assert_called()
    mock_class.method2.assert_not_called()

如果您需要方法有参数,它会变得有点复杂 - 您可以使用 side_effect 和相应的函数来代替:

@pytest.fixture
def mock_class(mocker):
    def method1(foo):
        return "method1 output " + foo

    def method2(foo):
        return "method2 output " + foo

    mock_class = mocker.MagicMock()
    mock_class.method1.side_effect = method1
    mock_class.method2.side_effect = method2
    yield mock_class