python-3.x 如何在pytest中Assert猴子补丁被调用?

huwehgph  于 2023-10-21  发布在  Python
关注(0)|答案(2)|浏览(103)

考虑以下情况:

class MockResponse:
    status_code = 200

    @staticmethod
    def json():
        return {'key': 'value'}
                                  # where api_session is a fixture
def test_api_session_get(monkeypatch, api_session) -> None:
    def mock_get(*args, **kwargs):
        return MockResponse()

    monkeypatch.setattr(requests.Session, 'get', mock_get)
    response = api_session.get('endpoint/') # My wrapper around requests.Session
    assert response.status_code == 200
    assert response.json() == {'key': 'value'}
    monkeypatch.assert_called_with(
        'endpoint/',
        headers={
            'user-agent': 'blah',
        },
    )

我如何Assert我正在修补的get'/endpoint'headers调用?当我现在运行测试时,我得到以下失败消息:
FAILED test/utility/test_api_session.py::test_api_session_get - AttributeError: 'MonkeyPatch' object has no attribute 'assert_called_with'
我做错了什么?感谢所有提前回复的人。

dzjeubhm

dzjeubhm1#

将添加另一个使用monkeyatch而不是“你不能使用monkeyatch”的响应
由于python有闭包,下面是我的穷人用moncluatch做这些事情的方法:

patch_called = False

def _fake_delete(keyname):
    nonlocal patch_called
    patch_called = True
    assert ...

monkeypatch.setattr("mymodule._delete", _fake_delete)
res = client.delete(f"/.../{delmeid}"). # this is a flask client
assert res.status_code == 200
assert patch_called

在你的例子中,因为我们正在做类似的事情来修补HTTP服务器的方法处理程序,你可以做类似的事情(不是说这很漂亮):

param_called = None

def _fake_delete(param):
    nonlocal param_called
    patch_called = param
    assert ...

monkeypatch.setattr("mymodule._delete", _fake_delete)
res = client.delete(f"/.../{delmeid}")
assert res.status_code == 200
assert param_called == "whatever this should be"
gopyfrb3

gopyfrb32#

您需要一个Mock对象来调用assert_called_with-monkeypatch不提供开箱即用的功能。您可以使用unittest.mock.patchside_effect来实现这一点:

from unittest import mock
import requests

...

@mock.patch('requests.Session.get')
def test_api_session_get(mocked, api_session) -> None:
    def mock_get(*args, **kwargs):
        return MockResponse()

    mocked.side_effect = mock_get
    response = api_session.get('endpoint/') 
    ...
    mocked.assert_called_with(
        'endpoint/',
        headers={
            'user-agent': 'blah',
        },
    )

仍然需要使用side_effect来获取mock对象(在本例中为mocked,类型为MagickMock),而不是仅在patch中设置自己的对象,否则将无法使用assert_called_...方法。

  • 澄清 :当我写“ Moncleratch does not provide that out of the box*”时,这与assert_called...方法的使用有关。这并不意味着你不能使用monthlatch来实现类似的功能,正如Tommy的回答中所展示的那样。

相关问题