Testing Exception Messages

The Python unittest module provides support for testing that an exception is raised using the assertRaises() method, but sometime we need to also test that the exception message is what is expected. Python v2.7 introduced the assertRaisesRegexp() method which can be used to test exception messages using regular expressions, but if you are stuck with v2.6 or earlier you will need to do something like:

import unittest


def raise_exception(yup=True):
    if yup:
        raise ValueError('Yup, exception raised.')


class BasicExceptionTest(unittest.TestCase):
    def test_message(self):
        try:
            raise_exception(True)
            self.fail()
        except ValueError as e:
            self.assertEqual(str(e), 'Yup, exception raised.')


if __name__ == '__main__':
    unittest.main(verbosity=2)

Looking at test_message() we first wrap the function we are testing (raise_exception()) in a try ... except statement to catch any exception that may be raised. If no exception is raised then we call fail() to signal that the test has failed. If the correct exception has been raised (in this case ValueError) we use assertEqual() to test that the exception message is correct. If an exception that we were not expecting is raised, then it will be handled by the TestCase class and the test will be marked as having an error. With this simple test pattern every possible outcome should be handled correctly.

If you plan to be writing a lot of these sorts of tests, then it may be worth creating your own TestCase class that provides an assert method for testing exception messages:

import unittest


def raise_exception(yup=True):
    if yup:
        raise ValueError('Yup, exception raised.')


class ExceptionMessageTestCase(unittest.TestCase):
    def assertRaisesMessage(self, exception, msg, func, *args, **kwargs):
        try:
            func(*args, **kwargs)
            self.fail()
        except exception as e:
            self.assertEqual(str(e), msg)


class MessageExceptionTest(ExceptionMessageTestCase):
    def test_message(self):
        self.assertRaisesMessage(ValueError, 'Yup, exception raised.',
                                 raise_exception, True)


if __name__ == '__main__':
    unittest.main(verbosity=2)

The assertRaisesMessage() method is very similar to the assertRaises() method except that it also takes a msg argument that will be used to compare against the exception message.

Both of these test patterns could also be extended to include the ability to use regular expression to test messages (similar to assertRaisesRegexp()), but I generally find that simple string comparisons are usually enough for my needs.