Testing exceptions
==================

.. currentmodule:: testfixtures

The :mod:`unittest` support for asserting that exceptions are raised
when expected is fairly weak. Like many other Python testing
libraries, TestFixtures has tools to help with this.

The :class:`ShouldRaise` context manager
----------------------------------------

If you are using a version of Python where the :keyword:`with`
statement can be used, it's recommended that you use the
:class:`ShouldRaise` context manager. 

Suppose we wanted to test the following function to make sure that the
right exception was raised:

.. code-block:: python

  def the_thrower(throw=True):
      if throw:
          raise ValueError('Not good!')

The following example shows how to test that the correct exception is
raised:

>>> from testfixtures import ShouldRaise
>>> with ShouldRaise(ValueError('Not good!')):
...     the_thrower()

If the exception raise doesn't match the one expected,
:class:`ShouldRaise` will raise an :class:`AssertionError`
causing the tests in which it occurs to fail:

>>> with ShouldRaise(ValueError('Is good!')):
...     the_thrower()
Traceback (most recent call last):
...
AssertionError: ValueError('Not good!',) raised, ValueError('Is good!',) expected

If you're not concerned about anything more than the type of the
exception that's raised, you can check as follows:

>>> from testfixtures import ShouldRaise
>>> with ShouldRaise(ValueError):
...     the_thrower()

If you're feeling slack and just want to check that an exception is
raised, but don't care about the type of that exception, the following
will suffice:

>>> from testfixtures import ShouldRaise
>>> with ShouldRaise():
...     the_thrower()

If no exception is raised by the code under test, :class:`ShouldRaise`
will raise an :class:`AssertionError` to indicate this:

>>> from testfixtures import ShouldRaise
>>> with ShouldRaise():
...     the_thrower(throw=False)
Traceback (most recent call last):
...
AssertionError: No exception raised!

:class:`ShouldRaise` has been implemented such that it can be
successfully used to test if code raises both :class:`SystemExit` and
:class:`KeyboardInterrupt` exceptions.
 
The :func:`should_raise` decorator
-----------------------------------------

If you are working in a traditional :mod:`unittest` environment and
want to check that a particular test function raises an exception, you
may find the decorator suits your needs better:
 
.. code-block:: python

  from testfixtures import should_raise
  
  @should_raise(ValueError('Not good!'))
  def test_function():
      the_thrower()

This decorator behaves exactly as the :class:`ShouldRaise` context
manager described in the documentation above.

.. note:: 

  It is slightly recommended that you use the context manager rather
  than the decorator in most cases. With the decorator, all exceptions
  raised within the decorated function will be checked, which can
  hinder test development. With the context manager, you can make
  assertions about only the exact lines of code that you expect to
  raise the exception.
