使用 pytest-mock 检查调用顺序

Checking call order with pytest-mock

在下面显示的代码片段中,我想测试 run() 函数中的函数调用顺序,即 f_3f_2 之后调用,在 f_2 之后调用14=]:

class TestMock:

    def f_1(self) -> None:
        pass

    def f_2(self) -> None:
        pass

    def f_3(self) -> None:
        pass

    def run(self) -> None:
        self.f_1()
        self.f_2()
        self.f_3()

有什么方法可以使用 pytest-mock 做到这一点吗?我试图在我的测试文件中模拟 f_1f_2f_3 函数,并将 assert_has_callsany_order=False 一起使用,但是没有成功。

提前感谢您的帮助或提示!

最好的, 阿列克谢

您在 any_order=False 方面走在了正确的轨道上,您只需要了解 attach_mock 功能:

import yourmodule

def test_something(mocker):
    mock = mocker.MagicMock()
    mock.attach_mock(mocker.patch("yourmodule.TestMock.f_1"), "f_1")
    mock.attach_mock(mocker.patch("yourmodule.TestMock.f_2"), "f_2")
    mock.attach_mock(mocker.patch("yourmodule.TestMock.f_3"), "f_3")
    yourinstance = yourmodule.TestMock()
    yourinstance.run()
    mock.assert_has_calls(
        [
            mocker.call.f_1(),
            mocker.call.f_2(),
            mocker.call.f_3(),
        ],
        any_order=False,
    )

我已经完全切换到 unittest.mock 并且现在有以下工作代码:

@mock.patch('.'.join([__name__, 'TestMock', 'f_3']))
@mock.patch('.'.join([__name__, 'TestMock', 'f_2']))
@mock.patch('.'.join([__name__, 'TestMock', 'f_1']))
def test_order_2(f_1: mock.NonCallableMock,
                 f_2: mock.NonCallableMock,
                 f_3: mock.NonCallableMock) -> None:
    manager = mock.Mock()
    manager.attach_mock(f_1, 'f_1')
    manager.attach_mock(f_2, 'f_2')
    manager.attach_mock(f_3, 'f_3')

    obj = TestMock()
    obj.run()

    manager.assert_has_calls([mock.call.f_1,
                              mock.call.f_2,
                              mock.call.f_3], any_order=False)

这里出现了问题:我不太理解属性名称背后的含义,所以它们是强制性的,但对我来说唯一合理的名称是函数名称本身。 .. 我修改了属性名称如下:

@mock.patch('.'.join([__name__, 'TestMock', 'f_3']))
@mock.patch('.'.join([__name__, 'TestMock', 'f_2']))
@mock.patch('.'.join([__name__, 'TestMock', 'f_1']))
def test_order_1(f_1: mock.NonCallableMock,
                 f_2: mock.NonCallableMock,
                 f_3: mock.NonCallableMock) -> None:
    manager = mock.Mock()
    manager.attach_mock(f_1, f_1._extract_mock_name())
    manager.attach_mock(f_2, f_2._extract_mock_name())
    manager.attach_mock(f_3, f_3._extract_mock_name())

    obj = TestMock()
    obj.run()

    manager.assert_has_calls([mock.call.f_1,
                              mock.call.f_2,
                              mock.call.f_3], any_order=False)

很高兴听到您对此的意见!

顺便问一下,为什么 f_* 模拟对象是 mock.NonCallableMoc 类型?我希望它们被虚拟函数取代 (Collable)...

再次感谢您的帮助!

最好的, 阿列克谢