Unittest 單元測試框架2 - 編寫測試代碼以及如何跳過測試用例

前文:
Unittest 單元測試框架1 - 基本使用和命令行選項


組織你的測試代碼

單元測試的構(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)系刪除

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市等孵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蹂空,老刑警劉巖俯萌,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異上枕,居然都是意外死亡咐熙,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進店門辨萍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來棋恼,“玉大人返弹,你說我怎么就攤上這事∽ζ” “怎么了义起?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長师崎。 經(jīng)常有香客問我默终,道長,這世上最難降的妖魔是什么犁罩? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任齐蔽,我火速辦了婚禮,結(jié)果婚禮上床估,老公的妹妹穿的比我還像新娘含滴。我一直安慰自己,他們只是感情好丐巫,可當我...
    茶點故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布谈况。 她就那樣靜靜地躺著,像睡著了一般鞋吉。 火紅的嫁衣襯著肌膚如雪鸦做。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天谓着,我揣著相機與錄音泼诱,去河邊找鬼。 笑死赊锚,一個胖子當著我的面吹牛治筒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播舷蒲,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼耸袜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了牲平?” 一聲冷哼從身側(cè)響起堤框,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎纵柿,沒想到半個月后蜈抓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡昂儒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年沟使,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片渊跋。...
    茶點故事閱讀 40,742評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡腊嗡,死狀恐怖着倾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情燕少,我是刑警寧澤卡者,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站棺亭,受9級特大地震影響虎眨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜镶摘,卻給世界環(huán)境...
    茶點故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一嗽桩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧凄敢,春花似錦碌冶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拒逮,卻和暖如春罐氨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背滩援。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工栅隐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人玩徊。 一個月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓租悄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親恩袱。 傳聞我的和親對象是個殘疾皇子泣棋,可洞房花燭夜當晚...
    茶點故事閱讀 45,747評論 2 361

推薦閱讀更多精彩內(nèi)容