4

在下面显示的代码片段中,我想测试函数中的函数调用顺序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_1f_2f_3函数并使用assert_has_callswith any_order=False,但是没有成功。

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

最好的,阿列克谢

4

2 回答 2

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,
    )
于 2020-08-27T20:12:39.953 回答
0

我现在已经完全切换到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)取代......

再次感谢您的帮助!

最好的,阿列克谢

于 2020-08-31T14:27:36.997 回答