Python assertRaises on user-defined exceptions
Asked Answered
S

2

4

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)
Speedway answered 18/2, 2016 at 19:36 Comment(2)
You defined two different MyException classes. You're not raising the same exception as the one you're trying to catch.Boogiewoogie
@VincentSavard If I were to remove the two lines in foobar_unittest.py that define MyException, then I would receive the following error: NameError: global name 'MyException' is not defined.Speedway
W
2

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
Whist answered 18/2, 2016 at 19:44 Comment(1)
Yes, that was the answer to the above issue. Thank you!Speedway
S
0

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?.

Solange answered 6/11, 2021 at 8:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.