Problem
How do you construct a unittest that only fails if a function fails to throw the anticipated exception?
Asked by Daryl Spitzer
Solution #1
Use the unittest module’s TestCase.assertRaises (or TestCase.failUnlessRaises) for example:
import mymod
class MyTestCase(unittest.TestCase):
def test1(self):
self.assertRaises(SomeCoolException, mymod.myfunc)
Answered by Moe
Solution #2
Since Python 2.7, you may obtain a hold of the actual Exception object thrown by using context manager:
import unittest
def broken_function():
raise Exception('This is broken')
class MyTestCase(unittest.TestCase):
def test(self):
with self.assertRaises(Exception) as context:
broken_function()
self.assertTrue('This is broken' in context.exception)
if __name__ == '__main__':
unittest.main()
http://docs.python.org/dev/library/unittest.html#unittest.TestCase.assertRaises
If you don’t surround context.exception with str in Python 3.5, you’ll get a TypeError.
self.assertTrue('This is broken' in str(context.exception))
Answered by Art
Solution #3
My prior answer’s code can be simplified to:
def test_afunction_throws_exception(self):
self.assertRaises(ExpectedException, afunction)
If a function accepts arguments, simply send them into assertRaises as follows:
def test_afunction_throws_exception(self):
self.assertRaises(ExpectedException, afunction, arg1, arg2)
Answered by Daryl Spitzer
Solution #4
Make use of your own resources. As a context manager, assertRaises:
def test_1_cannot_add_int_and_str(self):
with self.assertRaises(TypeError):
1 + '1'
In a Python shell, the best practice technique is quite simple to show.
The unittest library
Python 2.7 or Python 3:
import unittest
You may install a backport of Python 2.7’s unittest library, called unittest2, in Python 2.6 and just alias it as unittest:
import unittest2 as unittest
Now copy and paste the following type-safety test into your Python shell:
class MyTestCase(unittest.TestCase):
def test_1_cannot_add_int_and_str(self):
with self.assertRaises(TypeError):
1 + '1'
def test_2_cannot_add_int_and_str(self):
import operator
self.assertRaises(TypeError, operator.add, 1, '1')
AssertRaises is used as a context manager in Test 1, ensuring that the problem is caught and cleaned up appropriately while being recorded.
Test two shows how we could write it without the context manager. The error type you plan to raise is the first parameter, the second argument is the function you’re testing, and the remaining args and keyword args are sent to that function.
I believe that using the context manager is significantly more easy, readable, and manageable.
To conduct the tests, follow these steps:
unittest.main(exit=False)
You’ll probably need the following in Python 2.6:
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))
And the following should appear on your terminal:
..
----------------------------------------------------------------------
Ran 2 tests in 0.007s
OK
<unittest2.runner.TextTestResult run=2 errors=0 failures=0>
Attempting to add a 1 and a ‘1’ results in a TypeError, as we would anticipate.
For more verbose output, try this:
unittest.TextTestRunner(verbosity=2).run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))
Answered by Aaron Hall
Solution #5
This pattern should be followed in your code (this is a unittest module type test):
def test_afunction_throws_exception(self):
try:
afunction()
except ExpectedException:
pass
except Exception:
self.fail('unexpected exception raised')
else:
self.fail('ExpectedException not raised')
On Python < 2.7 this construct is useful for checking for specific values in the expected exception. The unittest function assertRaises only checks if an exception was raised.
Answered by Daryl Spitzer
Post is based on https://stackoverflow.com/questions/129507/how-do-you-test-that-a-python-function-throws-an-exception