組織你的測試代碼
單元測試的構(gòu)建單位是test cases: 獨立的,包含執(zhí)行條件與正確性檢查的方案。在unittest
中,測試用例表示為unittest.TestCase
的實例触徐。通過編寫TestCase
的子類或使用FunctionTestCase
編寫你自己的測試用例。
一個TestCase
實例的測試代碼必須是完全自含的省有,因此它可以獨立運行患雇,或與其他任意組合任意數(shù)量的測試用例一起運行前硫。
TestCase
最簡單的子類需要實現(xiàn)一個測試方法(例如一個明明以test
開頭的方法)以執(zhí)行特定的測試代碼:
import unittest
class DefaultWidgetSizeTestCase(unittest.TestCase):
def test_default_widget_size(self):
widget = Widget("The widget")
self.assertEqual(widget.size(), (50, 50))
可以看到临梗,為了進行測試涡扼,我們使用了基類TestCase
提供的一個assert*()
方法。若測試不通過盟庞,將會引發(fā)一個帶有說明信息的異常壳澳,并且unittest
會將這個測試用例標記為測試不通過。任何其他類型的異常將會被當做錯誤處理茫经。
可能同時存在多個前置操作相同的測試,我們可以把測試的前置操作從測試代碼中拆解出來萎津,并實現(xiàn)測試前置方法setUp()
卸伞。在運行測試時,測試框架會自動的為每個單獨測試調(diào)用前置方法锉屈。
import unittest
class WidgetTestCase(unittest.TestCase):
def setUp(self):
self.widget = Widget('The widget')
def test_default_widget_size(self):
self.assertEqual(self.widget.size(), (50, 50), 'incorrect default size')
def test_widget_resize(self):
self.widget.resize(100, 150)
self.assertEqual(self.widget.size(), (100, 150), 'wrong size after resize')
注解: 多個測試運行的順序由內(nèi)置字符串排序方法對測試名進行排序的結(jié)果決定. |
---|
在測試運行時荤傲,若setUp()
方法引發(fā)異常,測試框架會認為測試發(fā)生了錯誤颈渊,因此測試方法不會被運行遂黍。
相似的,我們提供了一個tearDown()
方法在測試方法運行后進行清理工作俊嗽。
import unittest
class WidgetTestCase(unittest.TestCase):
def setUp():
self.widget = Widget('The widget')
def tearDown(self):
self.widget.dispose()
若setUp()
成功運行雾家,無論測試方法是否成功,都會運行tearDown()
绍豁。
這樣的一個測試代碼運行的環(huán)境被稱為test fixture芯咧。一個新的TestCase
實例作為一個test fixture
, 用于運行各個獨立的測試方法。在運行每個測試時,setUp()
, tearDown()
和__init__()
會被調(diào)用一次敬飒。
建議你根據(jù)所測試的功能邪铲,將測試用TestCase實現(xiàn)集合起來。unittest
為此提供了機制:test suite
无拗, 以unittest
的類TestSuite
為代表带到。大部分情況下,調(diào)用unittest.main()
即可, 并且它會為你集合所有模塊的測試用例并執(zhí)行英染。
然而揽惹,如果你需要自定義你的測試套件的話,你可以參考以下方法組織你的測試:
def suite():
suite = unittest.TestSuite()
suite.addTest(WidgetTestCase('test_default_widget_size'))
suite.addTest(WidgetTestCase('tset_widget_resize'))
return suite
if __name__ == '__main__':
runner = unitest.TextTestRunner()
runner.run(suite())
您可以將測試用例和測試套件的定義與要測試的代碼放在相同的模塊中(例如 widget.py
), 但是將測試代碼放在單獨的模塊中有幾個優(yōu)點税迷,例如test_widget.py
:
測試模塊可以從命令行獨立運行永丝。
測試代碼可以更容易地從附帶的代碼中分離出來。
在沒有充分理由的情況下箭养,更改測試代碼以適應它所測試的代碼的誘惑就更少了慕嚷。
測試代碼的修改頻率應該比它測試的代碼少的多。
復用已有的測試代碼
一些用戶希望直接使用unittest
運行已有的測試代碼毕泌,而不需要把已有的每個測試函數(shù)轉(zhuǎn)化為一個TestCase
的子類喝检。
因此, unittest
提供FunctionTestCase
類撼泛。這個TestCase
的子類可用于打包已有的測試函數(shù)挠说,并支持設置前置與后置函數(shù)。
假定有一個測試函數(shù):
def testSomething():
something = makeSomething()
assert something.name is not None
# ...
可以創(chuàng)建等價的測試用例如下愿题, 其中前置和后置方法是可選的损俭。
testcase = unittest.FunctionTestCase(testSomething, setUp=markSomethingDB, tearDown=deleteSomethingDB)
注解: 即使可以使用FunctionTestCase 能夠被將現(xiàn)有的測試庫轉(zhuǎn)換為基于unitest的系統(tǒng),也不建議使用這種方法潘酗「吮花時間建立適當?shù)?code>TestCase子類將使將來的測試重構(gòu)變得更加容易。 |
---|
在某些情況下仔夺,現(xiàn)有的測試可能是使用doctest
模塊編寫的琐脏。如果是這樣,doctest
提供了一個DocTestSuite
類缸兔,可以自動生成unittest
. TestSuite
現(xiàn)有基于doctest
的測試的實例日裙。
跳過測試與預計的失敗
3.1 新版本功能
Unittest
支持跳過單個測試方法甚至跳過整個測試類。此外惰蜜,他還支持將測試標記為預期失敗
, 即可以被破壞并將失敗的測試昂拂,但不應再TestResult上被視為失敗。
跳過測試只是使用skip()
裝飾器或其變量之一抛猖,調(diào)用TestCase.skipTest()
在setUp()
或者測試方法政钟,或者直接跑出 SkipTest
.
跳過測試的基本用法如下:
import unittest
class MyTestCase(unittest.TestCase):
@unittest.skip("demonstrating skipping")
def test_nothing(self):
self.fail("shouldn't happen")
@unittest.skipIf(mylib.__version__ < (1, 3), "not supported in this library version")
def test_format(self)L
# Tests that work for only a certain version of the library
pass
@unittest.skipUnless(sys.platform.startwith("win"), "requires Windows")
def test_windows_support(self):
# windows specific testing code
pass
def test_maybe_skipped(self):
if not external_resource_available():
self.skipTest("external resource not available")
# test code that appends on the external resource
pass
在啰嗦模式下運行以上測試用例時路克,程序輸出如下:
test_nothing (__main__.MyTestCase) ... skipped 'demonstrating skipping'
test_maybe_skipped (__main__.MyTestCase) ... skipped 'external resource not available'
test_windows_support (__main__.MyTestCase) ... skipped 'requires Windows'
----------------------------------------------------------------------
Ran 4 tests in 0.005s
OK (skipped=4)
跳過測試類的寫法跟跳過測試方法的寫法相似:
@unittest.skip("showing class skipping")
class MySkippedTestCase(unittest.TestCase):
def test_not_run(self):
pass
TestCase.setUp()
也可以跳過測試⊙唬可以用于所需資源不可用的情況下跳過接下來的測試精算。
使用expectedFailure()
裝飾器表明這個測試預計失敗。:
class ExpectedFailureTestCase(unittest.TestCase):
@unittest.expectedFailure
def test_fail(self):
self.assertEqual(1, 0, "broken")
通過使一個decorator在測試中調(diào)用'skip()'碎连,當它想要跳過它時灰羽,就可以很容易地滾動您自己的跳過decorator。除非傳遞的對象具有特定屬性鱼辙,否則此devorator將跳過測試:
def skipUnlessHasattr(obj, attr):
if hasattr(obj, attr):
return lambda func:func
return unittest.skip("{!r} doesn't have {!r}".format(obj, attr))
以下裝飾器和異常實現(xiàn)了測試跳過和預期的失斄馈:
@unittest.skip(reason)
跳過被此裝飾器裝飾的測試用例, reason為測試被跳過的原因倒戏。@unittest.skipIf(condition, reason)
當condition為真時怠噪,跳過被裝飾的測試。@unittest.skipUnless(condition, reason)
跳過被裝飾的測試杜跷,除非condition為真傍念。@unittest.expectedFailure
將測試標記為預期錯誤。如果測試失敗或出錯將被視為成功葛闷。如果測試通過憋槐,則視為失敗。exception unitest.SkipTest(reason)
引發(fā)此異常以跳過一個測試淑趾。 通常來說阳仔,你可以使用TestCase.skipTest()
或其中一個跳過測試的裝飾器實現(xiàn)跳過測試的功能,而不是直接引發(fā)此異常扣泊。
被跳過的測試的setUp()
和tearDown()
不會被運行近范。被跳過的類和setUpClass()
和tearDownClass()
不會被運行。被跳過的模組的setUpModule()
和tearDownModule()
不會被運行延蟹。
原文來自于https://docs.python.org/3.9/library/unittest.html#
如有侵權(quán)评矩,請聯(lián)系刪除