Проверка порядка звонков с помощью pytest-mock

Во фрагменте кода, показанном ниже, я хотел бы проверить порядок вызова функций в run() функция, т.е. f_3 называется после f_2 что называется после f_1:

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_1, f_2, а также f_3 функции в моем тестовом файле и использовать assert_has_calls с участием any_order=FalseОднако безуспешно.

Заранее благодарим за любую помощь или подсказки!

С уважением, Алексей

2 ответа

Решение

Вы были на правильном пути с 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)...

Заранее спасибо за помощь!

С уважением, Алексей

Другие вопросы по тегам