python-3.x - 如何模拟引发 urllib 错误
问题描述
在python 文档中阅读此内容后,我发现了(通过调用)可以引发HTTPError
的URLError
异常:get_response_from_external_api
make_request_and_get_response
urllib
urlopen
foo.main.py
from urllib.request import urlopen
import contextlib
from urllib.error import HTTPError, URLError
def make_request_and_get_response(q):
with contextlib.closing(urlopen(q)) as response:
return response.read()
def get_response_from_external_api(q):
try:
resp = make_request_and_get_response(q)
return resp
except URLError as e:
print('Got a URLError: ', e)
except HTTPError as e:
print('Got a HTTPError: ', e)
if __name__ == "__main__":
query = 'test'
result = get_response_from_external_api(query)
print(result)
在测试该get_response_from_external_api
方法时,我试图模拟引发HTTPError
和URLError
异常:
foo.test_main.py
from foo.main import get_response_from_external_api
import pytest
from unittest.mock import patch, Mock
from urllib.error import HTTPError, URLError
def test_get_response_from_external_api_with_httperror(capsys):
with patch('foo.main.make_request_and_get_response') as mocked_method:
with pytest.raises(HTTPError) as exc:
mocked_method.side_effect = HTTPError() # TypeError
resp = get_response_from_external_api(mocked_method)
out, err = capsys.readouterr()
assert resp is None
assert 'HTTPError' in out
assert str(exc) == HTTPError
def test_get_response_from_external_api_with_urlerror(capsys):
with patch('foo.main.make_request_and_get_response') as mocked_method:
with pytest.raises(URLError) as exc:
mocked_method.side_effect = URLError() # TypeError
resp = get_response_from_external_api(mocked_method)
out, err = capsys.readouterr()
assert resp is None
assert 'URLError' in out
assert str(exc) == URLError
但我得到一个TypeError: __init__() missing 5 required positional arguments: 'url', 'code', 'msg', 'hdrs', and 'fp'
. 我是 python 模拟语法的新手,正在寻找示例。
我已经阅读了这个答案,但我看不到如何在我的情况下应用它,其中urllib.urlopen
(via get_response_from_external_api
) 的返回值超出了 except-block 的范围。不知道我是否应该像这里urllib.urlopen.read
看到的那样模拟整个?
解决方案
没有必要模拟部分urlopen
——通过模拟你的函数来引发一个异常,你可以确保它urlopen
不会被调用。
由于您正在创建这些异常以检查您的错误处理代码是否正常工作,因此它们不需要完整 - 它们只需要包含满足您的测试所需的最少信息。
HTTPError需要五个参数:
- 一个网址
- HTTP 状态码
- 错误信息
- 请求标头
- 一个类似文件的对象(响应的主体)
出于模拟目的,这些都可能是None
,但构造一个看起来像真正错误的对象可能会有所帮助。如果某些内容要读取“类文件对象”,您可以传递io.BytesIO
包含示例响应的实例,但这似乎没有必要,根据问题中的代码。
>>> h = HTTPError('http://example.com', 500, 'Internal Error', {}, None)
>>> h
<HTTPError 500: 'Internal Error'>
URLError需要一个参数,可以是字符串或异常实例;出于模拟目的,一个字符串就足够了。
>>> u = URLError('Unknown host')
>>> u
URLError('Unknown host')
这是问题中的代码,经过修改以考虑到上述内容。并且不需要将模拟函数传递给自身 - 只需传递任意字符串。我删除了这些with pytest.raises
块,因为在您的代码的 try/except 块中捕获了异常:您正在测试您的代码是否处理异常本身,而不是异常渗透到测试函数。
from foo.main import get_response_from_external_api
import pytest
from unittest.mock import patch, Mock
from urllib.error import HTTPError, URLError
def test_get_response_from_external_api_with_httperror(capsys):
with patch('foo.main.make_request_and_get_response') as mocked_method:
mocked_method.side_effect = HTTPError('http://example.com', 500, 'Internal Error', {}, None)
resp = get_response_from_external_api('any string')
assert resp is None
out, err = capsys.readouterr()
assert 'HTTPError' in out
def test_get_response_from_external_api_with_urlerror(capsys):
with patch('foo.main.make_request_and_get_response') as mocked_method:
mocked_method.side_effect = URLError('Unknown host')
resp = get_response_from_external_api('any string')
assert resp is None
out, err = capsys.readouterr()
assert 'URLError' in out
最后,你需要颠倒你的 try except blocks 的顺序 -HTTPError
是 的子类URLError
,所以你需要先对其进行测试,否则它会被except URLError
块处理。
推荐阅读
- sql - SQL 返回值出错(缺少参数)
- python - 子命令问题:ctx.invoked_subcommands 始终为 None
- python - 遍历列表直到满足 2 个条件
- c# - 为什么我在 UWP 中收到此错误“...无法解析程序集:System.Runtime”?
- python - 使用 pandas 和 fuzzwuzzy 匹配相似的列元素
- c# - 序列化异常返回一个非常大的 JSON
- python - 如何在 html div 中显示 Python print()
- mysql - SQL将值与特定年份的平均值进行比较
- python - 在 Kivy 中使用按钮释放清除 inputText
- amp-html - URL 中带有斜杠的 AMP 分析源