views:

1771

answers:

9

How does one write a test that fails only if a function doesn't throw an expected exception?

+3  A: 

Have a look at the assertRaises method of the unittest module.

Greg Hewgill
+15  A: 

Use TestCase.assertRaises (or TestCase.FailUnlessRaises) from the unittest module

see here: http://docs.python.org/library/unittest.html#unittest.TestCase.assertRaises

for example:

import mymod

class MyTestCase(unittest.TestCase):
    def test1(self):
        self.assertRaises(SomeCoolException, mymod.myfunc)
Moe
I used to really like assertRaises, but using it together with automatic refactoring tools (like rope) is problematic, as they don't understand those are arguments to the function you're passing. That's why we sometimes use assertRaises like so: assertRaises(Exception, lambda _: mymod.myfunc(arg1, arg2))
abyx
+2  A: 

Your code should follow this pattern (this is a unittest module style test):

def test_afunction_throws_exception(self):
    try:
        afunction()
    except ExpectedException:
        pass
    except e:
       self.fail('Unexpected exception thrown:', e)
    else:
       self.fail('ExpectedException not thrown')
Daryl Spitzer
+9  A: 

Wow! Questions get answered fast on stackoverflow.com! I'm glad I asked this.

The code in my previous answer can be simplified to:

def test_afunction_throws_exception(self):
    self.assertRaises(ExpectedException, afunction)

And if afunction takes arguments, just pass them into assertRaises like this:

def test_afunction_throws_exception(self):
    self.assertRaises(ExpectedException, afunction, arg1, arg2)
Daryl Spitzer
+1  A: 

See also: How do I unit test an init() method of a python class with assertRaises()?

Which presents some code for using the built in python unit testing framework for testing exception raising, beyond what is possible without extending.

Jerub
+3  A: 

I use doctest[1] almost everywhere because I like the fact that I document and test my functions at the same time.

Have a look at this code:

def throw_up(something, gowrong=False):
    """
    >>> throw_up('Fish n Chips')
    Traceback (most recent call last):
    ...
    Exception: Fish n Chips

    >>> throw_up('Fish n Chips', gowrong=True)
    'I feel fine!'
    """
    if gowrong:
        return "I feel fine!"
    raise Exception(something)

if __name__ == '__main__':
    import doctest
    doctest.testmod()

If you put this example in a module and run it from the command line both test cases are evaluated and checked.

[1] Python documentation: 23.2 doctest -- Test interactive Python examples

pi
A: 

I just discovered that the Mock library provides an assertRaisesWithMessage() method (in its unittest.TestCase subclass), which will check not only that the expected exception is raised, but also that it is raised with the expected message:

from testcase import TestCase

import mymod

class MyTestCase(TestCase):
    def test1(self):
        self.assertRaisesWithMessage(SomeCoolException,
                                     'expected message',
                                     mymod.myfunc)
Daryl Spitzer
A: 

Since Python 2.7 you can use context manager to get a hold of the actual Exception object thrown, which enables you check for various fields in the exception object, like message:

def broken_function():
    raise Exception('This is broken')

....


with self.assertRaises(MyException) as context:
    broken_function()

self.assertEqual(context.exception.message, 'This is broken')

http://docs.python.org/dev/library/unittest.html#unittest.TestCase.assertRaises

Art
A: 

You can use assertRaises from the unittest module

import unittest

class TestClass():
  def raises_exception(self):
    raise Exception("test")

class MyTestCase(unittest.TestCase):
  def test_if_method_raises_correct_exception(self):
    test_class = TestClass()
    # note that you dont use () when passing the method to assertRaises
    self.assertRaises(Exception, test_class.raises_exception)
Bruno Carvalho