当前位置: 首页 > 面试题库 >

无法捕获模拟异常,因为它不继承BaseException

常英资
2023-03-14
问题内容

我正在一个项目中,该项目涉及连接到远程服务器,等待响应,然后根据该响应执行操作。我们捕获了两个不同的异常,并且根据捕获的异常而表现不同。例如:

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,但得到的错误大致相同。

我已经读过,所以我认为它在__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您所没有的第一个信息,因为当您使用'requests.exceptions.ConnectionError': requests.exceptions.ConnectionErrorin强制使用真正的异常时,我正在提出一个模拟。但是问题仍然在于
except子句试图捕获一个模拟

TL / DR:在模拟完整requests程序包时,该except requests.exceptions.ConnectionError子句尝试捕获模拟。由于模拟不是真正的a
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方法,但有副作用。



 类似资料:
  • 我正在做的一个项目涉及到连接到远程服务器,等待响应,然后根据响应执行操作。我们捕获了几个不同的异常,并且根据捕获的异常的不同而有不同的行为。例如: 为了测试这一点,我们编写了一个如下所示的测试

  • 所以 我有一个函数,有一个回调,所以我把它包装在一个挂起函数使用,但当它错误了,它是崩溃整个应用程序。 这里有一个概念是正在发生的事情。 2022-03-04 16:09:45.410 19289-19438/in.app.androidE/AndreidRuntime: FATAL EXCEPTION: DefaultDispatcher-Worers-3进程:in.app.android,PI

  • 我正在尝试使用以下代码使用流 API 获取 S3 对象的文件大小: 如果该项不存在,我会得到以下错误: [2015年10月13日星期二23:03:32][错误][客户端54.225.205.152]PHP警告:找不到文件或目录:s3://mybucket/myfile.jpg在/var/www/vendor/Aws/Aws-SDK-PHP/src/Aws/S3/stream wrapper . P

  • 出于某种未知原因,当用户输入为字符串或特殊字符时,它不会捕获我的异常(扫描仪只接受整数和从1到3)。代码如下: 代码的结果是: 我搞不懂

  • 我这里有我的问题的简化版本。A类有一个受保护的方法。类B继承了这个方法。 我现在用Mockito编写一个单元测试,它在另一个包测试中,我想测试方法。为此,我需要模拟getString()调用。由于该方法受到保护,并且我的测试类位于不同的包中,所以我不能使用。问题是,我监视类B。所以我不能使用。 我尝试通过反射获得受保护的方法: 但是我不知道如何在中使用这个。

  • 我通过激发Baeldung在Spring Security页面上的防止暴力身份验证尝试,为我的登录服务实现了暴力阻止机制,如下所示: 当用户未经验证时,LoginService抛出InvalidCredentialException(),然后我试图在AuthenticationFailureListener类中捕获此异常: 当出现错误时,则登录测试服务。将调用loginFailed()方法。然而,