2009-06-28 17 views
5

我在學習Python,並一直試圖更多地瞭解Python的unittest模塊的細節。文檔包括以下內容:使用Python unittest,我該如何創建並使用「可返回測試套件的可調用對象」?

爲便於運行測試,因爲我們 將在後面看到,這是一個好主意, 每個測試模塊中提供一個可調用 對象返回已創建測試 套件:

def suite(): 
    suite = unittest.TestSuite() 
    suite.addTest(WidgetTestCase('testDefaultSize')) 
    suite.addTest(WidgetTestCase('testResize')) 
    return suite 

至於我可以告訴大家,這樣做的目的不是解釋。另外,我無法弄清楚如何使用這種方法。我試過幾件事情沒有成功(除了學習,我得到了錯誤消息):

import unittest 

def average(values): 
    return sum(values)/len(values) 

class MyTestCase(unittest.TestCase): 
    def testFoo(self): 
     self.assertEqual(average([10,100]),55) 

    def testBar(self): 
     self.assertEqual(average([11]),11) 

    def testBaz(self): 
     self.assertEqual(average([20,20]),20) 

    def suite(): 
     suite = unittest.TestSuite() 
     suite.addTest(MyTestCase('testFoo')) 
     suite.addTest(MyTestCase('testBar')) 
     suite.addTest(MyTestCase('testBaz')) 
     return suite 

if __name__ == '__main__': 
    # s = MyTestCase.suite() 
    # TypeError: unbound method suite() must be called 
    # with MyTestCase instance as first argument 

    # s = MyTestCase.suite(MyTestCase()) 
    # ValueError: no such test method in <class '__main__.MyTestCase'>: runTest 

    # s = MyTestCase.suite(MyTestCase('testFoo')) 
    # TypeError: suite() takes no arguments (1 given) 

下面的「工作」,但似乎尷尬,它要求我改變的suite()方法簽名爲「def suite(self):」。

s = MyTestCase('testFoo').suite() 
unittest.TextTestRunner().run(s) 

回答

6

你得到的第一個錯誤信息是有意義的,並解釋了很多。

print MyTestCase.suite # <unbound method MyTestCase.suite> 

不作承諾。這意味着除非將其綁定到實例,否則不能調用它。它實際上是同爲MyTestCase.run

print MyTestCase.run # <unbound method MyTestCase.run> 

也許現在你不明白,爲什麼你不能叫suite,但請把它放在一邊。你會嘗試在課程上撥打run,就像上面一樣嗎?例如:

MyTestCase.run() # ? 

可能不是吧?寫這個是沒有意義的,它不會工作,因爲run是一個實例方法,並且需要一個self實例來處理。那麼它看起來像Python「理解」suite一樣,它理解run,作爲一個未綁定的方法。

讓我們來看看爲什麼:

如果你嘗試把suite方法出類範圍的,並把它定義爲一個全球性的功能,它只是工作:

import unittest 

def average(values): 
    return sum(values)/len(values) 

class MyTestCase(unittest.TestCase): 
    def testFoo(self): 
     self.assertEqual(average([10,100]),55) 

    def testBar(self): 
     self.assertEqual(average([11]),11) 

    def testBaz(self): 
     self.assertEqual(average([20,20]),20) 

def suite(): 
    suite = unittest.TestSuite() 
    suite.addTest(MyTestCase('testFoo')) 
    suite.addTest(MyTestCase('testBar')) 
    suite.addTest(MyTestCase('testBaz')) 
    return suite 

print suite() # <unittest.TestSuite tests=[<__main__.MyTestCase testMethod=testFoo>, <__main__.MyTestCase testMethod=testBar>, <__main__.MyTestCase testMethod=testBaz>]> 

,但你不因爲你想打電話MyTestCase.suite()

你可能認爲,因爲suite是一種「靜態」,或與實例無關,它沒有意義,把self argume nt,是嗎? 是的。

但是,如果您在一個Python類中定義了一個方法,那麼Python會期望該方法將一個self參數作爲第一個參數。只是省略self參數不會自動使您的方法static。當你要定義一個「靜態」的方法,你必須使用staticmethod裝飾:

@staticmethod 
def suite(): 
    suite = unittest.TestSuite() 
    suite.addTest(MyTestCase('testFoo')) 
    suite.addTest(MyTestCase('testBar')) 
    suite.addTest(MyTestCase('testBaz')) 
    return suite 

這樣Python不認爲對MyTestCase爲實例方法,但作爲一個功能:

print MyTestCase.suite # <function suite at 0x...> 

而且當然現在你可以撥打MyTestCase.suite(),這將按預期工作。

if __name__ == '__main__': 
    s = MyTestCase.suite() 
    unittest.TextTestRunner().run(s) # Ran 3 tests in 0.000s, OK 
1

documentation是說suite()應該是模塊中的功能,而不是在你的類的方法。這似乎僅僅是一個方便的功能,使您可以爲許多模塊後總測試套件:

alltests = unittest.TestSuite([ 
    my_module_1.suite(), 
    my_module_2.suite(), 
]) 

你的問題,叫你的功能都與它是在類中的方法,尚不能寫成方法。 self參數是「當前對象」,並且是實例方法所必需的。 (例如,a.b(1, 2)在概念上與b(a, 1, 2)相同。)如果方法在類而不是實例上運行,請閱讀classmethod。如果它只是爲了方便而與班級分組,但不在班級和實例上操作,那麼請閱讀staticmethod。這些都不會特別幫助你使用unittest,但它們可能有助於解釋你爲什麼看到你做了什麼。

1

一兩件事,重要的是要注意,nose是一個工具,真正簡化了運行測試。它允許您準確指定從命令行運行哪些測試,以及遍歷每個目錄並運行每個測試。

1

如前所述,文檔將suite()作爲模塊中的一個方法,單元測試(奇怪)似乎對此方法沒有任何特別的認識,所以您必須明確地調用它。但是,如果使用名爲「testoob」的工具,它會自動調用suite()方法(如果您爲其main()指定defaultTest =「suite」參數並在基本unittest包頂部添加了其他幾個功能。它還提供了用於生成XML文件的選項,這些文件包括從這些測試中收集的stdout和stderr(這對於自動化測試而言是很大的優勢),並且還可以生成HTML報告(儘管您需要安裝其他軟件包)。我無法找到自動發現所有支持的測試的方法,因此鼻子可能是更好的選擇。

0

我會建議使用以下內容。這樣可以避免手動輸入您在添加時添加的所有測試。

def suite(): 
    suite = unittest.TestLoader().loadTestsFromTestCase(Your_Test_Case_Class) 
    return suite 

這使您可以通過定義執行同一模塊中的測試靈活性:

if __name__ == "__main__": 
    suite() 

如果你想你的捆綁套房,另一個模塊,即test_suite.py(例如),然後它可以通過以下方式進行:

進口test_module名 進口單元測試

if __name__=="__main__": 
    suite1=test_module_name.suite() 
    ... 
    ... 
    alltests = unittest.TestSuite([suite1,suite2]) 

現在如何運行你的測試。我一般用簡單的方式通過在封裝級執行此命令運行,單元測試自動發現測試:

python -m unittest discover 

nosetests 

警告:單元測試是X倍的速度那麼nosetest ,那麼就可以達到開發人員的偏好,特別是如果他們使用了第三方的nosetest插件並想繼續使用它。

相關問題