Can’t catch mocked exception because it doesn’t inherit BaseException

I could reproduce the error with a minimal example:

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"

Test without mocking :

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())

Ok, all is fine, both test pass

The problem comes with the mocks. As soon as the class MyError is mocked, the expect clause cannot catch anything and I get same error as the example from the question :

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())

Immediately gives :

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

Here I get a first TypeErrorthat you did not have, because I am raising a mock while you forced a true exception with 'requests.exceptions.ConnectionError': requests.exceptions.ConnectionError in config. But the problem remains that the except clause tries to catch a mock.

TL/DR: as you mock the full requests package, the except requests.exceptions.ConnectionError clause tries to catch a mock. As the mock is not really a BaseException, it causes the error.

The only solution I can imagine is not to mock the full requests but only the parts that are not exceptions. I must admit I could not find how to say to mock mock everything except this but in your example, you only need to patch requests.head. So I think that this should work :

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
        )

That is : only patch the head method with the exception as side effect.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)