我想知道我們什麼時候運行unittest.main()
,Python如何知道unittest.Testcase
有哪些子類?Python的unittest模塊如何檢測測試用例?
例如,如果我添加一個類FromRomanBadInput(unittest.TestCase)
,unittest
知道如何運行此?
我想知道我們什麼時候運行unittest.main()
,Python如何知道unittest.Testcase
有哪些子類?Python的unittest模塊如何檢測測試用例?
例如,如果我添加一個類FromRomanBadInput(unittest.TestCase)
,unittest
知道如何運行此?
'main'函數搜索所有繼承了導入模塊中unittest.TestCase的類。和電流路徑,然後嘗試運行每個與「測試」
從python's document開始方法:
import random
import unittest
class TestSequenceFunctions(unittest.TestCase):
def setUp(self):
self.seq = range(10)
def test_shuffle(self):
# make sure the shuffled sequence does not lose any elements
random.shuffle(self.seq)
self.seq.sort()
self.assertEqual(self.seq, range(10))
# should raise an exception for an immutable sequence
self.assertRaises(TypeError, random.shuffle, (1,2,3))
def test_choice(self):
element = random.choice(self.seq)
self.assertTrue(element in self.seq)
def test_sample(self):
with self.assertRaises(ValueError):
random.sample(self.seq, 20)
for element in random.sample(self.seq, 5):
self.assertTrue(element in self.seq)
if __name__ == '__main__':
unittest.main()
測試用例被通過繼承創建unittest.TestCase生成。三個 個別測試是用名稱以 字母測試開頭的方法定義的。該命名慣例通知測試運行者有關 哪些方法表示測試。
所以我環顧四周,我Python27/Lib
目錄...
unittest.main
實際上是一個類,unittest.TestProgram
的別名。所以會發生什麼是你構造一個這樣的實例,它的運行,它執行一系列的理智檢查和配置,包括動態導入你調用它的模塊(它使用__import__
函數,__main__
作爲名稱默認情況下要導入的模塊)。所以現在它有一個self.module
屬性,它包含一個代表你的源的模塊對象。
最終,它得到這個代碼:
self.test = self.testLoader.loadTestsFromModule(self.module)
其中self.testLoader
是unittest.TestLoader
一個實例。該方法包括,除其他的東西:
for name in dir(module):
obj = getattr(module, name)
if isinstance(obj, type) and issubclass(obj, case.TestCase):
tests.append(self.loadTestsFromTestCase(obj))
所以它使用你的模塊對象的dir
讓你定義(包括類)的全局變量,過濾器的名稱是剛剛從unittest.TestCase
派生的類(本地,case.TestCase
是這個的別名),然後查找這些類中的測試方法以添加到tests
列表中。該搜索的行爲相似:
def isTestMethod(attrname, testCaseClass=testCaseClass,
prefix=self.testMethodPrefix):
return attrname.startswith(prefix) and \
hasattr(getattr(testCaseClass, attrname), '__call__')
testFnNames = filter(isTestMethod, dir(testCaseClass))
所以它使用的類dir
獲得名嘗試的列表,查找與這些名字的屬性,並選擇那些與self.testMethodPrefix
(默認'test'
)開始,可調用的(具有__call__
屬性)。 (我真的很驚訝他們不使用內置的callable
函數,我想這是爲了避免拾取嵌套類)
哇。這是非常全面和有益的。感謝您的時間和精力! – stupidguy 2012-04-15 06:21:27
綜合,也許,但我真的不能想象它是如何**有用的**。文檔已經告訴你如何使用**'unittest',這應該是你真正需要知道的。 – 2012-04-16 10:02:32
@KarlKnechtel:呃,碰巧你確實**幫助我解決了這個問題。 :)我爲單元測試和整個測試用例編寫了一個裝飾器,並想知道爲什麼測試運行器不會執行裝飾測試用例。運行上面的代碼,我意識到我忘記了我的裝飾器(不帶參數)將我的unittest.TestCase子類轉換爲完全不同的對象... – balu 2014-05-30 16:10:55
我寫了一些代碼,試圖做的行爲類似於unittest.main( )以下。總之,我遍歷模塊,對於不以名稱'unittest'開頭的模塊,我檢查它的成員。然後,如果這些成員是一個類,並且是unittest.TestCase的子類,我通過該類的成員解析。然後,如果這些類的成員是以'test'開頭的函數或方法,我將它添加到測試列表中。類對象的__dict__
用於內省方法/函數,因爲使用inspect.getmembers可能會顯示太多。最後,這個測試列表被轉換爲一個元組,幷包裝爲一個套件。然後,該套件以冗長級別2運行。請注意,當然,刪除在函數/方法名稱開頭處檢查'test'的正則表達式可以將bar_test()包括到測試列表中如果你不想要這個限制。
#!/usr/bin/env python
import unittest
import inspect
import sys
import re
class Foo(unittest.TestCase):
@staticmethod
def test_baz():
pass
@classmethod
def test_mu(cls):
pass
def test_foo(self):
self.assertEqual('foo', 'foo')
def bar_test(self):
self.assertEqual('bar', 'bar')
class Bar:
pass
if __name__ == '__main__':
runner = unittest.TextTestRunner(verbosity=2)
tests = []
is_member_valid_test_class = lambda member: inspect.isclass(member) and \
issubclass(member, unittest.TestCase)
for module_name, module_obj in sys.modules.items():
if not re.match(r'unittest', module_name):
for cls_name, cls in inspect.getmembers(
module_obj, is_member_valid_test_class):
for methname, methobj in cls.__dict__.items():
if inspect.isroutine(methobj) and re.match(r'test', methname):
tests.append(cls(methname))
suite = unittest.TestSuite(tests=tuple(tests))
runner.run(suite)
產生的輸出是:
test_foo (__main__.Foo) ... ok
test_baz (__main__.Foo) ... ok
test_mu (__main__.Foo) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK
元類是涼的東西:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python – Amber 2012-04-11 03:43:23
解讀。非常感謝琥珀! – stupidguy 2012-04-11 04:08:52
@琥珀你是什麼意思? 'unittest'沒有單一的元類。 – bereal 2012-04-11 04:39:06