I\'m trying to run this test: self.assertRaises(AttributeError, branch[0].childrennodes)
, and branch[0
] does not have an attribute childrenno
When the test is running, before calling self.assertRaises, Python needs to find the value of all the method's arguments. In doing so, it evaluates branch[0].children_nodes
, which raises an AttributeError. Since we haven't invoked assertRaises yet, this exception is not caught, causing the test to fail.
The solution is to wrap branch[0].children_nodes
in a function or a lambda:
self.assertRaises(AttributeError, lambda: branch[0].children_nodes)
assertRaises 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 nice because 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.
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)
pytest also has a similar decorator:
from pytest import raises
def test_raising():
with raises(AttributeError):
branch[0].childrennodes
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