我正在一个项目中,该项目涉及连接到远程服务器,等待响应,然后根据该响应执行操作。我们捕获了两个不同的异常,并且根据捕获的异常而表现不同。例如:
def myMethod(address, timeout=20):
try:
response = requests.head(address, timeout=timeout)
except requests.exceptions.Timeout:
# do something special
except requests.exceptions.ConnectionError:
# do something special
except requests.exceptions.HTTPError:
# do something special
else:
if response.status_code != requests.codes.ok:
# do something special
return successfulConnection.SUCCESS
为了测试这一点,我们编写了如下测试
class TestMyMethod(unittest.TestCase):
def test_good_connection(self):
config = {
'head.return_value': type('MockResponse', (), {'status_code': requests.codes.ok}),
'codes.ok': requests.codes.ok
}
with mock.patch('path.to.my.package.requests', **config):
self.assertEqual(
mypackage.myMethod('some_address',
mypackage.successfulConnection.SUCCESS
)
def test_bad_connection(self):
config = {
'head.side_effect': requests.exceptions.ConnectionError,
'requests.exceptions.ConnectionError': requests.exceptions.ConnectionError
}
with mock.patch('path.to.my.package.requests', **config):
self.assertEqual(
mypackage.myMethod('some_address',
mypackage.successfulConnection.FAILURE
)
如果我直接运行该函数,一切都会按预期进行。我什至通过将raise requests.exceptions.ConnectionError
添加到函数的try
子句中进行了测试。但是当我运行单元测试时,我得到
ERROR: test_bad_connection (test.test_file.TestMyMethod)
----------------------------------------------------------------
Traceback (most recent call last):
File "path/to/sourcefile", line ###, in myMethod
respone = requests.head(address, timeout=timeout)
File "path/to/unittest/mock", line 846, in __call__
return _mock_self.mock_call(*args, **kwargs)
File "path/to/unittest/mock", line 901, in _mock_call
raise effect
my.package.requests.exceptions.ConnectionError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "Path/to/my/test", line ##, in test_bad_connection
mypackage.myMethod('some_address',
File "Path/to/package", line ##, in myMethod
except requests.exceptions.ConnectionError:
TypeError: catching classes that do not inherit from BaseException is not allowed
我试图更改我修补到BaseException
的异常,但得到的错误或多或少相同。
我已经读过https://stackoverflow.com/a/18163759/3076272,所以我认为它在某个地方一定是一个错误的__del__
钩子,但是我不确定在哪里可以找到它,或者我什至可以做些什么。我也是unittest.mock.patch()
的新手,所以很有可能在那做错了。
这是一个Fusion360插件,因此使用的是Fusion 360的打包版本的Python 3.3-据我所知,它是一个原始版本(即,他们不会自己滚动),但我对此并不乐观。
参考方案
我可以用一个最小的例子重现该错误:
foo.py:
class MyError(Exception):
pass
class A:
def inner(self):
err = MyError("FOO")
print(type(err))
raise err
def outer(self):
try:
self.inner()
except MyError as err:
print ("catched ", err)
return "OK"
测试时不要嘲笑:
class FooTest(unittest.TestCase):
def test_inner(self):
a = foo.A()
self.assertRaises(foo.MyError, a.inner)
def test_outer(self):
a = foo.A()
self.assertEquals("OK", a.outer())
好的,一切都很好,都通过了测试
问题来自模拟。一旦对类MyError进行了模拟,expect
子句就无法捕获任何内容,并且从问题中得到与示例相同的错误:
class FooTest(unittest.TestCase):
def test_inner(self):
a = foo.A()
self.assertRaises(foo.MyError, a.inner)
def test_outer(self):
with unittest.mock.patch('foo.MyError'):
a = exc2.A()
self.assertEquals("OK", a.outer())
立即给出:
ERROR: test_outer (__main__.FooTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "...\foo.py", line 11, in outer
self.inner()
File "...\foo.py", line 8, in inner
raise err
TypeError: exceptions must derive from BaseException
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<pyshell#78>", line 8, in test_outer
File "...\foo.py", line 12, in outer
except MyError as err:
TypeError: catching classes that do not inherit from BaseException is not allowed
在这里,我得到了您没有的第一个TypeError
,因为当您在config中使用'requests.exceptions.ConnectionError': requests.exceptions.ConnectionError
强制使用真正的异常时,我正在举一个模拟。但是问题仍然在于except
子句试图捕获模拟。
TL / DR:在模拟完整的requests
包时,except requests.exceptions.ConnectionError
子句尝试捕获模拟。由于模拟实际上不是BaseException
,因此会导致错误。
我能想象的唯一解决方案不是模拟完整的requests
,而是模拟并非例外的部分。我必须承认,除此以外,我找不到如何模拟所有内容的方法,但是在您的示例中,您只需要修补requests.head
即可。所以我认为这应该可行:
def test_bad_connection(self):
with mock.patch('path.to.my.package.requests.head',
side_effect=requests.exceptions.ConnectionError):
self.assertEqual(
mypackage.myMethod('some_address',
mypackage.successfulConnection.FAILURE
)
也就是说:仅修补head
方法,但有副作用。
在Python 3中,要加载以前保存的json,如下所示:json.dumps(dictionary)输出是这样的{"('Hello',)": 6, "('Hi',)": 5}当我使用json.loads({"('Hello',)": 6,…
Requests.get无法与&字符一起使用 - python我正在使用以下网址进行request.get调用:https://api.datasource.com/apps/ios/ranking?countries=NL&categories=Overall > Kids > 5 & Under&device=ios&ranks=1000 我收到"categor…
Python-使用请求时发布请求失败 - python使用外壳程序时,我可以通过运行以下命令成功创建新用户curl --user administrator:pasword "Content-Type: application/json" https://localhost:8080/midpoint/ws/rest/users -d @user.json但是,当我尝试使用请求在python…
Python uuid4,如何限制唯一字符的长度 - python在Python中,我正在使用uuid4()方法创建唯一的字符集。但是我找不到将其限制为10或8个字符的方法。有什么办法吗?uuid4()ffc69c1b-9d87-4c19-8dac-c09ca857e3fc谢谢。 参考方案 尝试:x = uuid4() str(x)[:8] 输出:"ffc69c1b" Is there a way to…
Python:无法识别Pip命令 - python这是我拍摄的屏幕截图。当我尝试在命令提示符下使用pip时,出现以下错误消息:pip无法识别为内部或外部命令,可操作程序或批处理文件。我已经检查了这个线程:How do I install pip on Windows?我所能找到的就是我必须将"C:\PythonX\Scripts"添加到我的类路径中,其中X代表python版本。如您在我的…