jef*_*tle 5 python unit-testing exception pytest python-requests
在我的python代码中,我期望在调用method之后可能引发异常requests.Session.request(),例如:
requests.exceptions.ConnectTimeout requests.exceptions.ReadTimeoutrequests.exceptions.Timeout当这些预期异常中的任何一个出现时,我都会适当地处理它们,例如可能重试。
我的问题是,我正在py.test用于单元测试,我故意要注入我代码中特定部分的引发异常。例如,调用requests.Session.request()而不是返回有效值的函数requests.Response将引发一个requests.exception。
我要确保我的代码成功处理来自其他程序包的预期和意外异常,其中包括来自的异常requests。
也许... @decorator我可以添加到上述功能中,以在单元测试期间根据要求引发异常吗?
有关为单元测试进行异常注入的建议?(对我的问题的正确措词将不胜感激。)
感谢您的答复!!!
这是创建requests.Session和调用的整个单例类requests.Session.request():
class MyRequest(metaclass=Singleton):
def __init__(self, retry_tries=3, retry_backoff=0.1, retry_codes=None):
self.session = requests.session()
if retry_codes is None:
retry_codes = set(REQUEST_RETRY_HTTP_STATUS_CODES)
self.session.mount(
'http',
HTTPAdapter(
max_retries=Retry(
total=retry_tries,
backoff_factor=retry_backoff,
status_forcelist=retry_codes,
),
),
)
def request(self, request_method, request_url, **kwargs):
try:
return self.session.request(method=request_method, url=request_url, **kwargs)
except Exception as ex:
log.warning(
"Session Request: Failed: {}".format(get_exception_message(ex)),
extra={
'request_method': request_method,
'request_url': request_url
}
)
raise
Run Code Online (Sandbox Code Playgroud)
小智 8
在我的应用程序中,我捕获异常requests.exceptions.ConnectionError
并返回下面变量中的消息expected。所以测试看起来像这样:
import pytest
import requests
expected = {'error': 'cant connect to given url'}
class MockConnectionError:
def __init__(self, *args, **kwargs):
raise requests.exceptions.ConnectionError
def test_project_method(monkeypatch):
monkeypatch.setattr("requests.get", MockConnectionError)
response = project_method('http://some.url.com/')
assert response == expected
Run Code Online (Sandbox Code Playgroud)
您可以使用 py.test raises,请在此处查看:http ://doc.pytest.org/en/latest/assert.html#assertions-about-expected-exceptions
考虑到您的代码,您可以按照以下方式做一些事情:
from requests.exceptions import ConnectTimeout, ReadTimeout, Timeout
from unittest.mock import patch
import pytest
class TestRequestService:
@patch('path_to_module.MyRequest')
def test_custom_request(self, my_request_mock):
my_request_mock.request.side_effect = ConnectTimeout
with pytest.raises(ConnectTimeout):
my_request_mock.request(Mock(), Mock())
Run Code Online (Sandbox Code Playgroud)
此外,您还可以使用 pytest.parametrize( http://doc.pytest.org/en/latest/parametrize.html ):
from requests.exceptions import ConnectTimeout, ReadTimeout, Timeout
from unittest.mock import patch
import pytest
class TestRequestService:
@pytest.mark.parametrize("expected_exception", [ConnectTimeout, ReadTimeout, Timeout])
@patch('path_to_module.MyRequest')
def test_custom_request(self, my_request_mock, expected_exception):
my_request_mock.request.side_effect = expected_exception
with pytest.raises(expected_exception):
my_request_mock.request(Mock(), Mock())
Run Code Online (Sandbox Code Playgroud)
在这里你可以找到更多关于参数化的例子:http : //layer0.authentise.com/pytest-and-parametrization.html