2009-08-13 55 views
19

我试图运行此测试:self.assertRaises(AttributeError, branch[0].childrennodes)branch[0]没有属性childrennodes,所以它应该抛出一个AttributeErrorassertRaises应该捕获,但是当我运行测试时,测试失败,因为它是投掷一个AttributeError为什么assertRaises使用python unittest捕捉我的属性错误?

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' 

任何想法?

回答

19

我认为它是因为断言提出只接受可调用。它可以评估可调用是否会引发异常,而不是语句本身是否会引发异常。

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

应该工作。

编辑:

由于THC4k正确地说,聚集在收集时间的语句,而将错误,那么,不是测试时间。

这也是为什么我喜欢鼻子的原因,它有一个装饰(提出),这对于这些测试是有用和清晰的。

@raises(AttributeError) 
def test_1(self) 
    branch[0].childrennodes 
+2

这就是正确的解决方案,但发生异常时Python将参数收集到'self.assertRaises'。它必须在调用函数之前评估'branch [0] .childrennodes'',这会引发异常,就像预期的那样。 – 2009-08-13 19:46:56

+0

unittest也有类似的功能。我用自己的回答描述了他们。拥抱! – 2010-09-23 16:38:31

48

当测试运行时,在调用self.assertRaises之前,Python需要找到所有方法参数的值。在这样做时,它评估branch[0].children_nodes,这引发了一个AttributeError。由于我们尚未调用assertRaises,因此未捕获此异常,导致测试失败。

的解决方案是包装在一个功能branch[0].children_nodes或λ:

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

assertRaises也可用作上下文管理器(因为Python 2.7,或在PyPI中包 'unittest2'):

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

这很好,因为它可以在测试过程中用于任意代码块,而不必创建一个新函数来定义它所应用的代码块。

它可以给你访问引发的异常进行进一步的处理,如果需要的话:

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

self.assertEquals(cm.exception.special_attribute, 123) 
+3

拉姆达超级优雅,感谢发布此:) – 2011-01-20 21:10:23

1

pytest也有类似的装饰:

from pytest import raises 

def test_raising(): 
    with raises(AttributeError): 
     branch[0].childrennodes