2010-01-06 36 views
0

使用unittest.assertRaises時遇到了一個奇怪的問題。當執行下面的代碼時,我得到以下輸出:assertRaises剛剛捕捉到基本異常

E 
====================================================================== 
ERROR: testAssertRaises (__main__.Test) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "C:\home\python_test\src\derived.py", line 29, in testAssertRaises 
    self.assertRaises(MyError, self.raiser.raiseMyError) 
    File "C:\Programme\Python26\lib\unittest.py", line 336, in failUnlessRaises 
    callableObj(*args, **kwargs) 
    File "C:\home\python_test\src\derived.py", line 15, in raiseMyError 
    raise MyError("My message") 
MyError: 'My message' 

---------------------------------------------------------------------- 
Ran 1 test in 0.000s 

FAILED (errors=1) 

正確的異常被引發,但測試失敗!如果我趕上BaseError測試成功。

不知何故,這似乎是單元測試的範圍問題,無法看到MyError異常類。有人可以解釋嗎?有一些解決方法嗎?

我正在測試下面的Python代碼,它是通過類名動態構建對象的實現。

這是基本模塊 「bases.py」:

class BaseClass(object): 

    @staticmethod 
    def get(className): 
     module = __import__("derived", globals(), locals(), [className]) 
     theClass = getattr(module, className) 
     return theClass() 


class BaseError(Exception): 

    def __init__(self, msg): 
     self.msg = msg 

    def __str__(self): 
     return repr(self.msg) 

這是測試模塊, 「derived.py」:

import unittest 

from bases import BaseError 
from bases import BaseClass 


class MyErrorRaiser(BaseClass):  

    def raiseMyError(self): 
     raise MyError("My message") 


class MyError(BaseError): 
    ''' 
    ''' 


class Test(unittest.TestCase): 

    def setUp(self): 
     self.raiser = BaseClass.get("MyErrorRaiser") 

    def testAssertRaises(self): 
     self.assertRaises(MyError, self.raiser.raiseMyError) 


if __name__ == "__main__": 
    unittest.main() 

回答

1

運行derived.py時,它將作爲__main__模塊運行(因爲您直接運行它而不是導入它)。當您稍後將其明確導入時,將創建該模塊的另一個副本,此時名稱爲derived。所以__main__.MyErrorderived.MyError不一樣,並且沒有發現異常。

+0

啊,這是有道理的。任何想法如何更好地實現呢?我已經注意到,如果將異常移動到單獨的模塊,它就可以工作。 – desolat 2010-01-06 13:25:34

+0

移動異常將解決此問題,但您仍然有相同模塊的兩個不同副本,並且稍後可能會出現其他問題。您需要以某種方式確保主模塊不會被其他模塊導入。我不知道爲什麼你需要'BaseClass.get'方法,所以我不能告訴你如何改進它,除了避免在單元測試中調用它。 – interjay 2010-01-06 13:46:06

0

這個問題可能是你的BaseClass.get()方法正在讓你回到另一個班。順便說一句,這種方法本身很糟糕,我想知道你爲什麼這樣做。

+0

是的,這是它的目的。這只是一個完整代碼的簡單示例,它是一種用於通過名稱實例化接口實現的抽象工廠。無論如何,如果你能幫助我解決我的問題,或者提供更好的實施,而不僅僅是咆哮,我將不勝感激。 – desolat 2010-01-06 13:23:27

+0

「只是咆哮」?我指出,問題可能是'BaseClass.get()'返回的是你傳遞給'assertRaises'的另一個類。 'assertRaises'沒有錯。現在如果你不喜歡對你的代碼或設計風格發表評論的人,那麼請不要在互聯網上發佈編程問題。 – 2010-01-06 13:53:53

+0

如果你會跑上面的代碼,你會發現這不是問題。如果你沒有解決問題,不要回答你不明白的問題。請參閱接受的答案,瞭解如何操作。 – desolat 2010-01-06 14:26:58

2

作爲mentioned,這個問題是模塊__main__衍生不是同一個;這個答案是關於你如何解決這個問題。

不要混合模塊代碼和腳本代碼。開始考慮將if __name__ == "__main__"代碼作爲破解。 (它有時候還是非常方便的,我經常用它來進行調試等等,但是它是一種黑客攻擊,所以你總是可以輕輕地寫出它的精神微調)。然後運行所有東西的新腳本將會很簡單(並從未進口):

#!/usr/bin/env python 
import derived 
import sys 
sys.exit(derived.main(sys.argv[1:])) 

或與個人喜好的各種差異。只要確保你添加了derived.main就可以做你想做的事。

我也看到了另一個黑客是不常見的,在derived.py的頂部

import sys 
if __name__ == "__main__": 
    import derived # import the same module under its "correct" name 
    sys.exit(derived.main(sys.argv[1:])) 

而在解析相同的代碼兩次浪費,這是自包含的交流。