Python assertRaises on user-defined exceptions

5.3k views Asked by At

The following question was triggered by the discussion in this post.

Assume two files (foobar.py and foobar_unittest.py). File foobar.py contains a class (FooBar) with two functions (foo and bar). Function bar raises a built-in exception, function foo a user-defined exception.

# foobar.py
class MyException(Exception):
    pass
class FooBar:
    def __init__(self):
        pass
    def bar(self):
        raise ValueError('Hello World.')
    def foo(self):
        raise MyException('Hello World.')

.

# foobar_unittest.py
import unittest
import foobar as fb
class MyException(Exception):
    pass
class FooBarTestCases(unittest.TestCase):
    def test_bar(self):
        with self.assertRaises(ValueError):
            fb.FooBar().bar()
    def test_foo(self):
        with self.assertRaises(MyException):
            fb.FooBar().foo()
if __name__ == '__main__':
    unittest.main()

When running unit-test on foobar.py, why does the function raising the user-defined exception (foo) fail to pass the test?

>>> python2.7 foobar_unittest.py 
.E
======================================================================
ERROR: test_foo (__main__.FooBarTestCases)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "foobar_unittest.py", line 11, in test_foo
    fb.FooBar().foo()
  File "/a_path/foobar.py", line 9, in foo
    raise MyException('Hello World.')
MyException: Hello World.

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (errors=1)
2

There are 2 answers

1
AlokThakur On BEST ANSWER

import MyException from foobar, don't redefine it.

import unittest
from foobar import MyException
import foobar as fb

class FooBarTestCases(unittest.TestCase):
    def test_bar(self):
        with self.assertRaises(ValueError):
            fb.FooBar().bar()
    def test_foo(self):
        with self.assertRaises(MyException):
            fb.FooBar().foo()
if __name__ == '__main__':
    unittest.main()

This code should work now as

..
----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK
0
Dennis Proksch On

Be aware that the same happens (happened to me) if you use reload to import your exceptions.

In my unittests I have the relevant imports like

from importlib import reload
import foobar
reload(foobar)
from foobar import MyException

This does not work, too, for whatever reason. Writing this just as

from foobar import MyException

will work. Then, of course, you have to reload the modules yourself.

In case you wonder why I am using reload: How do I unload (reload) a Python module?.