2009-08-13 31 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