Having trouble with Mock and exception side effects

Joshua J. Kugler joshua at azariah.com
Fri Aug 21 18:27:40 EDT 2020


Hello!  I am using Mock to raise an exception in an function as a side effect. 
However, Mock is completely redefining the exception itself turning it in to a 
MagickMock object, which generates the Python exception

TypeError: catching classes that do not inherit from BaseException is not 
allowed

This is my minimal reproducible test case.

# test_case.py
#!/usr/bin/python3

from unittest.mock import patch

import package.module

print('Before patcher start:', package.module.MyException)

patcher = patch('package.module')
mock_hvac = patcher.start()

print('After patcher start:', package.module.MyException)

try:
    print('Right before raise:', package.module.MyException)
    raise package.module.MyException

except package.module.MyException:
    print('Got the exception')

package/__init__.py
# Empty

package/module.py
class MyException(BaseException):
    pass

Output:
$ python3.6 --version
Python 3.6.9
$ python3.6 test_case.py
Before patcher start: <class 'package.module.MyException'>
After patcher start: <MagicMock name='module.MyException' 
id='140188666285696'>
Right before raise: <MagicMock name='module.MyException' id='140188666285696'>
Traceback (most recent call last):
  File "test_case.py", line 21, in <module>
    raise package.module.MyException
TypeError: exceptions must derive from BaseException

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test_case.py", line 23, in <module>
    except package.module.MyException:
TypeError: catching classes that do not inherit from BaseException is not 
allowed

This is also causing problems for Mock side effects. In this line of code in 
mock.py (line 997 for me):

        if effect is not None:
            if _is_exception(effect):
                raise effect

The _is_exception() function checks for an exception via:

    return (
        isinstance(obj, BaseExceptions) or
        isinstance(obj, type) and issubclass(obj, BaseExceptions)
    )

Which of course is false, because it's been replaced by a MagicMock object, so 
exception side effects aren't properly raised.

According to https://docs.python.org/3.6/library/unittest.mock.html#calling 
calling a function after setting the side_effect should raise the Exception, 
not a MagicMock object.

https://docs.python.org/3.6/library/unittest.mock.html#unittest.mock.Mock also 
says "Alternatively side_effect can be an exception class or instance. In this 
case the exception will be raised when the mock is called."

So, this seems to be not behaving as design, or at least not as documented. 
This is creating some really serious problems for testing our code, as we want 
a function to have a side effect of an Exception, and catch that exception, but 
we can do neither when it has been replaced by a MagicMock object.

Thanks for any tips, pointers, or "You're doing it wrong!" education. :)

j


-- 
Joshua J. Kugler - Fairbanks, Alaska - joshua at azariah.com
Azariah Enterprises - Programming and Website Design
PGP Key: http://pgp.mit.edu/  ID 0x68108cbb73b13b6a




More information about the Python-list mailing list