nosetest exception helper

May 13, 2008 – 16:14

Last night, enhancing the Chytach, I’ve again come across a feeling that standard nose asserts and decorators are not quite useful when testing exceptions.

For example, when I’m checking a django form validation, I’d like to make sure that my form throws a ValidationError (easy part) with a particular message (oops).

Nose proposes assert_raises for in-line checking and raises decorator. What I need is a raises with an additional pluggable check.

To make a long story short, here’s the usage example:

@testtools.raises(lambda e: check_validation_msg(e, 'Can\'t open "OMG'),
                  forms.forms.ValidationError)
def test_http_error(self):
    'opml throws IOError'
    forms.opml.parse = lambda x: testtools.raise_exc(IOError)
    self.form.cleaned_data = {'url' : 'OMG, they\'ve killed Kenny'}
    self.form.clean_url()

where checkvalidationmsg is a simple assert:

def check_validation_msg(exc, message):
    assert list(exc.messages)[0].startswith(message), list(exc.messages)

Here’s the docstring from testtools.raises:

"""Test must raise one of expected exceptions to pass.
The raised exception should pass callback check.

Example use::

  def callback(exc):
      assert exc.args[0] == 'This test passes'

  @raises(callback, TypeError, ValueError)
  def test_raises_type_error():
      raise TypeError("This test passes")

  @raises(callback, TypeError, ValueError)
  def test_fails_by_assert():
      raise TypeError("This test fails")

  @raises(callback, Exception):
  def test_that_fails_by_passing():
      pass

If you want to test many assertions about exceptions in a single test,
you may want to use `assert_raises` instead.
"""

You may download the working version here: testtools.py May 2008