p3试机号彩吧助手 ?
實驗:Unittest高級應用
作者:強官濤   類型:Python開發    類別:實驗   日期:2019-01-29    閱讀:998 次   消耗積分:0 分

1.TestSuite


TestSuite類用來對測試用例進行組合分類,通常稱為測試套件。我們可以將不同位置的測試用例集合到一個測試套件內,并利用其內部實現的run方法來執行。


為了直觀的理解TestSuite的用法,下面先定義了兩個測試類。每個測試類里分別定義了幾個方法。


import unittest

class TestDemo01(unittest.TestCase):

    def test01(self):

        print('This is test01.')

    def test02(self):

        print('This is test02.')

    def test03(self):

        print('This is test03.')

class TestDemo02(unittest.TestCase):

    def test04(self):

        print('This is test04.')

    def test05(self):

        print('This is test05.')


在執行的代碼段中,首先加入TestDemo01中的test02方法來構建出測試套件suite01,然后重新構建一個測試套件suite02,包含suite01與TestDemo02中的test04方法共同構成的一個元組。最后使用run方法將執行的結果保存到r變量中。這里需要特別說明,tests的參數類型必須是可迭代的,例如本例中的列表和元組。


if __name__ == '__main__':

    suite01 = unittest.TestSuite(tests=[TestDemo01('test02')])

    suite02 = unittest.TestSuite(tests=(suite01,TestDemo02('test04')))

    r = unittest.TestResult()

    suite02.run(result=r)

    print(r.__dict__)


本例中調用的是suite02中的run方法,那么運行的是suite02套件內的測試用例,依次為test02和test04。


This is test02.

This is test04.

{'failfast': False, 'failures': [], 'errors': [], 'testsRun': 2, 'skipped': [], 'expectedFailures': [], 'unexpectedSuccesses': [], 'shouldStop': False, 'buffer': False, 'tb_locals': False, '_stdout_buffer': None, '_stderr_buffer': None, '_original_stdout': <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>, '_original_stderr': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, '_mirrorOutput': False, '_testRunEntered': False, '_moduleSetUpFailed': False, '_previousTestClass': <class '__main__.TestDemo02'>}


TestSuite類中除了run()以外,還有一些重要的方法:addTest(test)和addTests(tests)。addTest(test)為添加測試用例,參數可以是TestCase或TestSuite的實例。addTests(tests)顧名思義,是對TestCase或TestSuite的實例的多個迭代進行添加,其內部實現原理依然是調用addTest(test)。簡單點說,前者是添加單個測試用例,而后者是為了一次性添加多個測試用例。


依然沿用TestDemo01和TestDemo02的例子,執行代碼做了一些調整,首先得到測試套件實例suite,分別調用addTest和addTests方法來添加測試用例,注意在addTests中只有一個參數,并且類型是元組,最后執行并輸出測試結果的字典。這里也額外使用了另外一個TestSuite中的常用方法countTestCases(),作用是返回執行的測試方法的個數。


if __name__ == '__main__':

    suite = unittest.TestSuite()

    suite.addTest(TestDemo01('test02'))

    suite.addTests((TestDemo02('test04'),TestDemo02('test05')))

    r = unittest.TestResult()

    suite.run(result=r)

print(r.__dict__)

print(suite.countTestCases())


執行結果不再贅述,仍然是依次執行添加的各個測試用例,然后輸出總共執行的測試方法個數3。


This is test02.

This is test04.

This is test05.

{'failfast': False, 'failures': [], 'errors': [], 'testsRun': 3, 'skipped': [], 'expectedFailures': [], 'unexpectedSuccesses': [], 'shouldStop': False, 'buffer': False, 'tb_locals': False, '_stdout_buffer': None, '_stderr_buffer': None, '_original_stdout': <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>, '_original_stderr': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, '_mirrorOutput': False, '_testRunEntered': False, '_moduleSetUpFailed': False, '_previousTestClass': <class '__main__.TestDemo02'>}

3

 

2.TestLoader


TestLoader是Unittest框架中的一個重要的類,可以從被測試的類和模塊中創建測試套件,即TestSuite。通常我們不用對他進行實例化,使用匿名對象的方式來使用即可。TestLoader中提供了如下一些常用的方法。


(1)loadTestsFromTestCase(testCaseClass) :從某個類中加載所有的測試方法,參數為加載的類名,testCaseClass必須繼承于TestCase。


(2)loadTestsFromModule(module, pattern=None) :從某個模塊中加載所有的測試方法,參數為模塊名,即文件名。當該模塊中有多個類都繼承于TestCase時,那么這些類里的測試方法均會被執行。


(3)loadTestsFromName(name, module=None) :加載某個單獨的測試方法,參數name是一個string,格式為“module.class.method”。


(4)loadTestsFromNames(name, module=None) :names是一個list,用法與上面相同。

下面依然沿用前面計算器的例子來進行講解。模塊名為Test01.py,代碼中被測試類為Calculator,TestDemo01與TestDemo02均為測試類,并繼承于unittest.TestCase,每個測試類中各有一個測試方法。在執行的代碼中,分別使用類名、模塊名、方法的方式來加載要測試的方法,并添加到了測試集suite中,最后執行測試集。


import unittest

# 導入當前的Test01模塊,用于后續使用

from C03_Unittest.Ex03_TestLoader import Test01

class Calculator:

    def divide(self,x,y):

        return x / y

class TestDemo01 (unittest.TestCase):

    def test01(self):

        print('This is test01.')

        cal = Calculator()

        result = cal.divide(10,2)

        self.assertEqual(result,5)

class TestDemo02(unittest.TestCase):

    def test02(self):

        print('This is test02.')

        cal = Calculator()

        result = cal.divide(0,2)

        self.assertEqual(result,0)

if __name__ == '__main__':

    suite = unittest.TestSuite()

    # 加載該類

    testCase01 = unittest.TestLoader().loadTestsFromTestCase(TestDemo01)

    # 加載整個模塊

    testCase02 = unittest.TestLoader().loadTestsFromModule(Test01)

    # 加載TestDemo01類中的測試方法test01

    testCase03 = unittest.TestLoader().loadTestsFromName('C03_Unittest.Ex03_TestLoader.Test01.TestDemo01.test01')

    suite.addTests(testCase01)

    suite.addTests(testCase02)

    suite.addTests(testCase03)

    r = unittest.TestResult()

    suite.run(result=r)

    print(r.__dict__)


運行結果如下,未出現失敗和錯誤。仔細分析可以看到,由于先執行suite.addTests(testCase01), TestDemo01類中的方法被運行了,輸出了“This is test01.”。接下來執行suite.addTests(testCase02),整個模塊即Test01.py里的所有測試方法被執行,所以分別輸出了“This is test01.”和“This is test02.”。最后加載的是testCase03,而他僅僅只是TestDemo01中的方法test01,所以又輸出了一次“This is test01.”。

 

This is test01.

This is test01.

This is test02.

This is test01.

{'failfast': False, 'failures': [], 'errors': [], 'testsRun': 4, 'skipped': [], 'expectedFailures': [], 'unexpectedSuccesses': [], 'shouldStop': False, 'buffer': False, 'tb_locals': False, '_stdout_buffer': None, '_stderr_buffer': None, '_original_stdout': <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>, '_original_stderr': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, '_mirrorOutput': False, '_testRunEntered': False, '_moduleSetUpFailed': False, '_previousTestClass': <class 'C03_Unittest.Ex03_TestLoader.Test01.TestDemo01'>}


其實在TestLoader中,還有其他的方法,比如discover,可以找到某個目錄下的所有測試模塊下的測試方法,這里就不詳細介紹,請大家自行查看官網文檔掌握其用法。

 

3.裝飾器


在unittest中提供了裝飾器的功能,比如我們想跳過某些方法的執行,或者直接設置某些方法為預期失敗的,這時就會用到裝飾器。對需要處理的方法的前一行加上諸如“@XX”,則可以實現相應的功能,常用的裝飾器有以下幾種。


(1)@unittest.skip(reason):無條件跳過測試,reason描述為什么跳過測試。

(2)@unittest.skipif(conditition,reason):condititon為條件,當條件為true時則跳過測試。

(3)@unittest.skipunless(condition,reason):condition為條件,與上面相反,當條件不是true時則跳過測試。

(4)@unittest.expectedFailure():標記該測試預期為失敗 ,如果該測試方法運行失敗,則該測試不算做失敗。

 

沿用前面的例子,分別對4個方法設置不同的裝飾器。


import unittest

import sys

class Calculator:

    def divide(self,x,y):

        return x / y

class TestDemo (unittest.TestCase):

    def setUp(self):

        self.a = 10

        self.b = 20

    @unittest.skip('強制跳過')

    def test01(self):

        print('This is test01.')

        cal = Calculator()

        result = cal.divide(10,2)

        self.assertEqual(result,3)

    @unittest.skipIf( 10 > 5, "滿足條件則跳過")

    def test02(self):

        print('This is test02.')

        cal = Calculator()

        result = cal.divide(10,2)

        self.assertEqual(result,3)

    @unittest.skipUnless( 10 > 5, "不滿足條件則跳過")

    def test03(self):

        print('This is test03.')

        cal = Calculator()

        result = cal.divide(10,2)

        self.assertEqual(result,3)

    @unittest.expectedFailure

    def test04(self):

        print('This is test04.')

        cal = Calculator()

        result = cal.divide(10,2)

        self.assertEqual(result,3)

if __name__ == '__main__':

    suite = unittest.TestSuite()

    # 加載整個類中的測試方法

    testCase = unittest.TestLoader().loadTestsFromTestCase(TestDemo)

    suite.addTests(testCase)

    r = unittest.TestResult()

    suite.run(result=r)

    print(r.__dict__)


運行結果如下。四個方法都分別設置了裝飾器,可以看到被跳過的是前兩個,第三個方法test03由于條件不滿足,正常執行,第四個方法也執行了,但即使失敗也沒有計入到failures中。


This is test03.

This is test04.

{'failfast': False, 'failures': [(<__main__.TestDemo testMethod=test03>, 'Traceback (most recent call last):\n  File "C:/Users/Administrator/PycharmProjects/python364/C03_Unittest/Ex05_Skip/Test01.py", line 32, in test03\n    self.assertEqual(result,3)\nAssertionError: 5.0 != 3\n')], 'errors': [], 'testsRun': 4, 'skipped': [(<__main__.TestDemo testMethod=test01>, '強制跳過'), (<__main__.TestDemo testMethod=test02>, '滿足條件則跳過')], 'expectedFailures': [(<__main__.TestDemo testMethod=test04>, 'Traceback (most recent call last):\n  File "C:/Users/Administrator/PycharmProjects/python364/C03_Unittest/Ex05_Skip/Test01.py", line 39, in test04\n    self.assertEqual(result,3)\nAssertionError: 5.0 != 3\n')], 'unexpectedSuccesses': [], 'shouldStop': False, 'buffer': False, 'tb_locals': False, '_stdout_buffer': None, '_stderr_buffer': None, '_original_stdout': <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>, '_original_stderr': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, '_mirrorOutput': False, '_testRunEntered': False, '_moduleSetUpFailed': False, '_previousTestClass': <class '__main__.TestDemo'>}


4.TestResult


顧名思義,TestResult類是為了保存測試結果而專門設計的。從前面的例子可知,執行測試時最終都需要調用run函數,而run函數則必須傳入一個參數result,這個result就是TestResult對象或者是其子類的對象。下面是run方法的源碼實現,代碼較長,只貼出一部分,目錄是讓大家明確result是run方法的必須參數。


    def run(self, result, debug=False):

        topLevel = False

        if getattr(result, '_testRunEntered', False) is False:

            result._testRunEntered = topLevel = True

        ...

        ...

             return result


我們單獨貼出核心的代碼段讓大家理解,r為TestResult的實例,無論是以何種方式調用run方法,都需要將TestResult實例化的對象作為參數傳遞給run。


if __name__ == '__main__':

    suite = unittest.TestSuite()

    suite.addTests((TestDemo02('test04'),TestDemo02('test05')))

    r = unittest.TestResult()

    suite.run(result=r)

    print(r.__dict__)


TestResult的內容非常豐富,對測試結果做了詳細的分類,下面的運行結果大家一定不會陌生,在前面的若干個例子里都出現過類似的部分。


{'failfast': False, 'failures': [], 'errors': [], 'testsRun': 3, 'skipped': [], 'expectedFailures': [], 'unexpectedSuccesses': [], 'shouldStop': False, 'buffer': False, 'tb_locals': False, '_stdout_buffer': None, '_stderr_buffer': None, '_original_stdout': <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>, '_original_stderr': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, '_mirrorOutput': False, '_testRunEntered': False,'_moduleSetUpFailed': False, '_previousTestClass': <class '__main__.TestDemo02'>}

3


TestResult的屬性幾乎涵蓋了我們需要對當前測試了解的所有信息,下面抽取其中最重要的屬性來進行解釋。


(1)failfast:值為True或False,當設置為True時,測試過程中遇到失敗或者錯誤,則立即終止后續的測試,通常我們保持False即可。

(2)failures:失敗,這里會列出使用斷言方法失敗的情況。

(3)errors:錯誤,這里會列出程序出現的異常錯誤。

(4)testsRun:已經運行的所有測試的數量。

(5)skipped:列出跳過的測試方法及原因。

(6)expectedFailures:列出預期失敗的方法。

(7)unexpectedSuccesses:列出標記為預期失敗,但實際運行卻又成功的方法。



為了答謝大家對蝸牛學院的支持,蝸牛學院將會定期對大家免費發放干貨,敬請關注蝸牛學院的官方微信。


20181009_153045_341.jpg


版權所有,轉載本站文章請注明出處:蝸牛學院在線課堂, http://www.ozqapw.tw/note/267
上一篇: 資訊:程序員薪資這么高,有封頂的嗎?
下一篇: 資訊:今天,蝸牛學院全是人人人人人人…
提示:登錄后添加有效評論可享受積分哦!
p3试机号彩吧助手 吕梁赖子麻将下载 集乐库影视网-在线观看最新热门影片 一本道快播成人电影 广西快三 快播在线看日本av电影网 pk10定位胆人工 股票配资推荐就择卓信宝配资优异 奥运会足球比赛比分 快乐8 成人黄色片图 江西微乐麻将官方网站 青海快3 麻将来了之前的版本 江苏十一选五奖结果 紫金矿业股票分析 衡阳足浴特殊服务