views:

522

answers:

2

I'm trying to run this test: self.assertRaises(AttributeError, branch[0].childrennodes), and branch[0] does not have an attribute childrennodes, so it should be throwing an AttributeError, which the assertRaises should catch, but when I run the test, the test fails because it is throwing an AttributeError.

Traceback (most recent call last):
  File "/home/tttt/../tttt/tests.py", line 504, in test_get_categories_branch
    self.assertRaises(AttributeError, branch[0].children_nodes)
AttributeError: 'Category' object has no attribute 'children_nodes'

Any ideas?

+2  A: 

I think its because assert raises only accepts a callable. It evalutes to see if the callable raises an exception, not if the statement itself does.

self.assertRaises(AttributeError, getattr, branch[0], "childrennodes")

should work.

EDIT:

As THC4k correctly says it gathers the statements at collection time and will error then, not at testing time.

Also this is a reason why I like nose, it has a decorator (raises) that is useful and clearer for these kind of tests.

@raises(AttributeError)
def test_1(self)
    branch[0].childrennodes
David Raznick
Thats the right solution, but the exception happens when Python collects the arguments to `self.assertRaises`. It has to evaluate `branch[0].childrennodes` before calling the function, which raises an exception just as expected.
THC4k
unittest has similar features too. I've described them in my own answer. Hugs!
Tartley
+3  A: 

Alternatively:

self.assertRaises(AttributeError, lambda: branch[0].children_nodes)

Also, as an alternative to the nose '@raises' decorator mentioned above, unittest's assertRaises method can also be used as a context manager (Since Python 2.7, or in PyPI package 'unittest2'):

with self.assertRaises(AttributeError):
    branch[0].children_nodes
    # etc

This is preferable to nose's decorator in my opinion, since it can be used on arbitrary blocks of code in the middle of a test, rather than having to create a new function just to define the block of code to which it applies. Also, it can give you access to the raised exception for further processing, if needed:

with self.assertRaises(AttributeError) as cm:
    branch[0].children_nodes

self.assertEquals(cm.exception.special_attribute, 123)
Tartley