[英]With Python unittest, how do I create and use a “callable object that returns a test suite”?
我正在學習Python,並且一直在努力了解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)
您獲得的第一條錯誤消息是有意義的,並解釋了很多。
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
論證是沒有意義的,是嗎? 這是正確的。
但是如果你在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
文檔說suite()
應該是模塊中的一個函數,而不是類中的方法。 它似乎只是一個便利功能,因此您以后可以聚合許多模塊的測試套件:
alltests = unittest.TestSuite([
my_module_1.suite(),
my_module_2.suite(),
])
調用函數的問題都與它在類中的方法有關,但不是作為方法編寫的。 self
參數是“當前對象”,並且是實例方法所必需的。 (例如ab(1, 2)
在概念上與b(a, 1, 2)
。)如果方法對類而不是實例進行操作,請閱讀有關classmethod
。 如果它只是為了方便而與類分組但不對類或實例進行操作,那么請閱讀staticmethod
。 這些都不會特別有助於您使用unittest
,但它們可能有助於解釋您為何看到自己所做的事情。
需要注意的一件事是, 鼻子是一種真正簡化運行測試的工具。 它允許您准確指定從命令行運行哪些測試,以及遍歷每個目錄並運行每個測試。
正如已經提到的,文檔將suite()稱為模塊中的方法,而unittest(奇怪地)似乎沒有對此方法進行任何特殊識別,因此您必須明確地調用它。 但是,如果使用名為“ testoob ”的工具,它會自動調用suite()方法(如果為main()指定defaultTest =“suite”參數),並在基本unittest包之上添加其他幾個功能。 它還提供了生成XML文件的選項,這些文件包括從這些測試中收集的stdout和stderr(這對於自動化測試來說是一大優點),並且還可以生成HTML報告(盡管您需要安裝其他軟件包)。 我找不到一種方法來自動發現鼻子聲稱支持的所有測試,所以鼻子可能是更好的選擇。
我建議使用以下內容。 這使您無需手動輸入隨時添加的所有測試。
def suite():
suite = unittest.TestLoader().loadTestsFromTestCase(Your_Test_Case_Class)
return suite
這使您可以通過定義以下內容靈活地在同一模塊中執行測試:
if __name__ == "__main__":
suite()
如果你想將套件捆綁在另一個模塊中,例如test_suite.py(例如),那么可以通過以下方式完成:
import test_module name import unittest
if __name__=="__main__":
suite1=test_module_name.suite()
...
...
alltests = unittest.TestSuite([suite1,suite2])
現在如何運行測試。 我通常使用更簡單的方法在包級別執行此命令來運行,並且unittest自動發現測試:
python -m unittest discover
要么
nosetests
警告:單元測試比鼻子測試速度快X倍,因此它取決於開發人員的偏好,特別是如果他們使用了第三方鼻子插件並想繼續使用它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.