如何断言在pytest中调用了一个猴子补丁?
How to assert a monkey patch was called in pytest?
考虑以下几点:
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',
},
)
我如何断言我正在修补的 get
会被 '/endpoint'
和 headers
调用?当我 运行 现在测试时,我收到以下失败消息:
FAILED test/utility/test_api_session.py::test_api_session_get - AttributeError: 'MonkeyPatch' object has no attribute 'assert_called_with'
我在这里做错了什么?感谢所有提前回复的人。
您需要一个 Mock
对象来调用 assert_called_with
- monkeypatch
没有提供。您可以使用 unittest.mock.patch
和 side_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
来获取模拟对象(mocked
在这种情况下,类型为 MagickMock
),而不是仅仅在 [=19= 中设置您自己的对象],否则您将无法使用 assert_called_...
方法。
将添加另一个使用 monkeypatch 而不是“你不能使用 monkeypatch”的回复
由于 python 有闭包,下面是我这个可怜的人用 monkeypatch 做这些事情的方法:
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"
考虑以下几点:
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',
},
)
我如何断言我正在修补的 get
会被 '/endpoint'
和 headers
调用?当我 运行 现在测试时,我收到以下失败消息:
FAILED test/utility/test_api_session.py::test_api_session_get - AttributeError: 'MonkeyPatch' object has no attribute 'assert_called_with'
我在这里做错了什么?感谢所有提前回复的人。
您需要一个 Mock
对象来调用 assert_called_with
- monkeypatch
没有提供。您可以使用 unittest.mock.patch
和 side_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
来获取模拟对象(mocked
在这种情况下,类型为 MagickMock
),而不是仅仅在 [=19= 中设置您自己的对象],否则您将无法使用 assert_called_...
方法。
将添加另一个使用 monkeypatch 而不是“你不能使用 monkeypatch”的回复
由于 python 有闭包,下面是我这个可怜的人用 monkeypatch 做这些事情的方法:
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"