unittest單元測試框架入門及應用

一、簡介

  unittest是Python單元測試框架。unittest它支援自動化測試,在測試中使用setup(初始化)和shutdown(關閉銷毀)操作,組織測試 用例為套件(批量運行),以及把測試和報告獨立開來。

  測試腳手架(test fixture):為了開展一項或多項測試所需要進行的準備工作,以及所有相關的清理操作。

  測試用例(test case):一個測試用例是一個獨立的測試單元。檢查輸入特定的數據時的響應。 unittest 提供一個基類: TestCase ,用於新建測試用例。

  測試套件(test suite):一系列的測試用例。用于歸檔需要一起執行的測試用例。

  測試運行器(test runner):一個用於執行和輸出測試結果的組件

   綜上,整個流程就是首先要寫好TestCase,然後由TestLoader載入TestCase到TestSuite,然後由TextTestRunner來運行TestSuite,運行的結果保存在TextTestResult中,整個過程集成在unittest.main模組中。

  官方文檔://docs.python.org/zh-cn/3.7/library/unittest.html

二、unittest類的屬性

  unittest.TestCase:TestCase類,所有測試用例類繼承的基本類。

  unittest.main():使用她可以方便的將一個單元測試模組變為可直接運行的測試腳本,main()方法使用TestLoader類來搜索所有包含在該模組中以「test」命名開頭的測試方法,並自動執行他們。執行方法的默認順序是:根據ASCII碼的順序載入測試用例,數字與字母的順序為:0-9,A-Z,a-z。所以以A開頭的測試用例方法會優先執行,以a開頭會後執行。

  unittest.TestSuite():unittest框架的TestSuite()類是用來創建測試套件的。

  unittest.TextTextRunner():unittest框架的TextTextRunner()類,通過該類下面的run()方法來運行suite所組裝的測試用例,入參為suite測試套件。

  unittest.defaultTestLoader(): defaultTestLoader()類,通過該類下面的discover()方法可自動更具測試目錄start_dir匹配查找測試用例文件(test*.py),並將查找到的測試用例組裝到測試套件,因此可以直接通過run()方法執行discover。

  unittest.skip():裝飾器,當運行用例時,有些用例可能不想執行等,可用裝飾器暫時屏蔽該條測試用例。一種常見的用法就是比如說想調試某一個測試用例,想先屏蔽其他用例就可以用裝飾器屏蔽。

三、跳過測試與預計的失敗

@unittest.skip(reason)

  跳過被此裝飾器裝飾的測試。 reason 為測試被跳過的原因。

@unittest.skipIf(condition, reason)

  當 condition 為真時,跳過被裝飾的測試。

@unittest.skipUnless(condition, reason)

  跳過被裝飾的測試,除非 condition 為真。

@unittest.expectedFailure

  把測試標記為預計失敗。如果測試不通過,會被認為測試成功;如果測試通過了,則被認為是測試失敗。

四、常用的斷言方法

 五、unittest實例

  我們就來上手,舉個簡單的例子來看看unittest裡面的屬性、函數與用例如何運行的。

 1 # 導入unittest模組
 2 import unittest
 3 
 4 # unittest.TestCase:TestCase類,所有測試用例類繼承的基本類。
 5 class TestStringCase(unittest.TestCase):
 6     # TestCase基類方法,所有case執行之前自動執行
 7     @classmethod
 8     def setUpClass(self):
 9         print("這裡是所有測試用例前的準備工作")
10 
11     # TestCase基類方法,所有case執行之後自動執行
12     @classmethod
13     def tearDownClass(self):
14         print("這裡是所有測試用例後的清理工作")
15 
16     # TestCase基類方法,每次執行case前自動執行
17     def setUp(self):
18         print("這裡是一個測試用例前的準備工作")
19 
20     # TestCase基類方法,每次執行case後自動執行
21     def tearDown(self):
22         print("這裡是一個測試用例後的清理工作")
23 
24     @unittest.skip("我想臨時跳過這個測試用例.")
25     # 測試用例1
26     def test_case1(self):
27         print('執行測試用例1')
28         s = 'hello'
29         self.assertEqual(s, "hello")
30 
31     # 測試用例2
32     def test_case2(self):
33         print('執行測試用例2')
34         s = '測試'
35         self.assertEqual(s, '測試')
36 
37     # 測試用例3
38     def test_case3(self):
39         print('執行測試用例3')
40         s= 'ceshi'
41         self.assertEqual(s, 'ceshi')
42 
43 #測試用例集合方法
44 def suite():
45     #實例化測試套件
46     suite = unittest.TestSuite()
47     #將用例加到用例集及運行順序
48     suite.addTest(TestStringCase('test_case3'))
49     suite.addTest(TestStringCase('test_case2'))
50     return suite
51 
52 #path= './' 定義測試集所在文件夾
53 #pattern='unittest_Two.py' 規定測試集文件
54 #discover方法找到path 目錄下所有文件到的測試用例組裝到測試套件
55 def discover():
56     path = './'
57     rundiscover = unittest.defaultTestLoader.discover(path,pattern='unittest_Two.py')
58     return rundiscover
59     
60 if __name__ == "__main__":
61     #運行用例方法一:
62     unittest.main()
63     
64     #運行用例方法二:
65     #實例化TextTestRunner類
66     #runner = unittest.TextTestRunner()
67     #runner.run(suite())
68 
69     #運行用例方法三:
70     #實例化TextTestRunner類
71     #runner = unittest.TextTestRunner()
72     #run()方法執行discover
73     #runner.run(discover())

  unittest實例方法一運行的結果:

 

   列印中前面的實心點,表示用例斷言成功並通過,s則表示跳轉執行用例。

  unittest實例方法二運行的結果:

  unittest實例方法三運行的結果同方法一結果所示。

六、生成測試報告

  知道了用例如何編寫,那麼我們來看看unittest的測試報告,這裡我介紹的是經大神改進後的HTMLTestRunnerCN,由於HTMLTestRunner樣式簡陋,我們不做介紹。

  Github下載HTMLTestRunnerCN://github.com/findyou/HTMLTestRunnerCN

  我用的是python3.x,注意下載後用3.x下面的HTMLTestRunnerCN。Git上的文件名叫HTMLTestReportCN.py。

  下載文件然後存放到你的Python安裝目錄中:\Lib\site-packages目錄下即可。程式碼中如何使用呢?在上面用例的基礎上,修改為下面的程式碼。如下所示。

 1 if __name__ == "__main__":
 2     filePath ='D:\\Report.html'       #確定生成報告的路徑
 3     fp = open(filePath,'wb')
 4     runner = HTMLTestReportCN.HTMLTestRunner(
 5         stream=fp,
 6         title='自動化測試報告', 
 7         #description='測試用例結果描述',    #不傳默認為空
 8         tester='wuwei'     #測試人員名字
 9         )
10     runner.run(discover())

  正常運行py用例文件,python XX.py,系統會在D盤下自動創建一個文件名為Report.html的html測試報告。上述實例運行的測試報告結果如下圖所示。

  備註:剛開始應用測試報告時,不知道有沒有小夥伴發現。用例列表中的失敗與通過的按鈕展示都是紅色,但是我想成功為綠色,失敗為紅色。我這裡稍微修改了一下HTMLTestRunnerCN.py的源碼。 
原程式碼:

1 tmpl = has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL

修改為:

1 tmpl = (n == 0 and self.REPORT_TEST_NO_OUTPUT_TMPL or self.REPORT_TEST_WITH_OUTPUT_TMPL)

  找至成功按鈕展示列表邏輯。
修改為:

 1 # 通過 的樣式,加標籤效果
 2     REPORT_TEST_NO_OUTPUT_TMPL = r"""
 3 <tr id='%(tid)s' class='%(Class)s'>
 4     <td class='%(style)s'><div class='testcase'>%(desc)s</div></td>
 5     <td colspan='5' align='center'>
 6     <button id='btn_%(tid)s' type="button"  class="btn btn-success btn-xs" data-toggle="collapse" data-target='#div_%(tid)s'>%(status)s</button>
 7     <div id='div_%(tid)s' class="collapse in">
 8     <pre>
 9     %(script)s
10     </pre>
11     </div>
12     </td>
13 </tr>
14 """ # variables: (tid, Class, style, desc, status)    

  大家可以根據自己的需求來修改HTMLTestRunnerCN.py的源碼,來實現自己的需要的測試報告樣式與需求。

七、requests介面測試應用unittest實例

  上面的Demo實例不過癮,我們來看看python requests介面測試如何來應用unittest實例的。下面我列舉的是一個慕課網的搜索介面,普通的Get請求的實例,涉及應用到介面調用,上面說明兩個簡單的用例,斷言及上述HTMLTestReportCN生成的測試報告。

 1 # 導入os、unittest、requests、HTMLTestReportCN模組
 2 import requests
 3 import unittest
 4 import os
 5 import HTMLTestReportCN
 6 
 7 # 發送Get請求方法
 8 def sendGet(url, paramData):
 9     result = requests.get(url=url, params=paramData).json()
10     return result
11 
12 # unittest.TestCase:TestCase類,所有測試用例類繼承的基本類。
13 class TestRequestOne(unittest.TestCase):
14     # 每次case執行前,調用介面地址
15     def setUp(self):
16         print("這裡是一個測試用例前的準備工作")
17         #介面地址
18         self.url = '//www.imooc.com/search/history'
19 
20     def tearDown(self):
21         print("這裡是一個測試用例後的清理工作")
22 
23     # 測試用例1
24     def test_api1(self):
25         resultData = sendGet(url=self.url, paramData={'words': 'test'})
26         # 用例斷言
27         self.assertEqual(resultData['data'][0]['word'], "testng")
28 
29     # 測試用例2
30     def test_api2(self):
31         resultData = sendGet(url=self.url, paramData={'words': '測試'})
32         # 用例斷言
33         self.assertEqual(resultData['data'][0]['word'], "測試你好")
34 
35 #測試用例集合方法
36 def suite():
37     #實例化測試套件
38     suite = unittest.TestSuite()
39     #將用例加到用例集及運行順序
40     suite.addTest(TestRequestOne('test_api2'))
41     suite.addTest(TestRequestOne('test_api1'))
42     return suite
43 
44 if __name__ == "__main__":
45     filePath = 'D:\\Report.html'  # 確定生成報告的路徑
46     fp = open(filePath, 'wb')
47     runner = HTMLTestReportCN.HTMLTestRunner(
48         stream=fp,
49         title='簡單介面自動化測試報告',
50         description='簡單介面自動化測試用例結果',    #不傳默認為空
51         tester='wuwei'  # 測試人員名字,不傳默認為QA
52     )
53     runner.run(suite())

  上述測試用例運行結果的測試報告如下:

八、seleniumWeb自動化應用unittest實例

  上面我們用unittest進行了介面測試的實例應用,下面我們就來看看unittest如何在seleniumWeb自動化中應用的。我們以百度首頁為例來進行web自動化測試,搜索並進行斷言,生成對應的測試報告。

 1 # 導入os、unittest、requests、HTMLTestReportCN模組
 2 from selenium import webdriver
 3 import unittest
 4 import os
 5 import HTMLTestReportCN
 6 import time
 7 
 8 # unittest.TestCase:TestCase類,所有測試用例類繼承的基本類。
 9 class TestSeleniumOne(unittest.TestCase):
10     # 每次case執行前,調用介面地址
11     def setUp(self):
12         print("這裡是一個測試用例前的準備工作")
13         #chrome實例,打開瀏覽器網頁
14         self.driver = webdriver.Chrome()
15         self.driver.get('//www.baidu.com')
16 
17     def tearDown(self):
18         print("這裡是一個測試用例後的清理工作")
19         #每個用例執行後關閉瀏覽器
20         self.driver.quit()
21 
22     # 測試用例1
23     def test_selenium1(self):
24         # 利用find_element_by_id定位元素位置並模擬按鍵輸入「部落格園」,點擊百度一下按鈕搜索,斷言
25         self.driver.find_element_by_id("kw").send_keys("部落格園")
26         self.driver.find_element_by_id("su").click()
27         time.sleep(5)
28         resultTest = self.driver.find_element_by_xpath("//*[@id='1']/h3").text
29         self.assertEqual(resultTest,"部落格園 - 開發者的網上家園官方")
30 
31     # 測試用例2
32     def test_selenium2(self):
33         # 利用find_element_by_id定位元素位置並模擬按鍵輸入「測試」,點擊百度一下按鈕搜索,斷言
34         self.driver.find_element_by_id("kw").send_keys("測試")
35         self.driver.find_element_by_id("su").click()
36         time.sleep(5)
37         resultTest = self.driver.find_element_by_xpath("//*[@id='3001']/div[1]/h3").text
38         self.assertEqual(resultTest,"ceshi_前景如何?博為峰16年專註軟體測試培訓")
39 
40 #測試用例集合方法
41 def suite():
42     #實例化測試套件
43     suite = unittest.TestSuite()
44     #將用例加到用例集及運行順序
45     suite.addTest(TestSeleniumOne('test_selenium1'))
46     suite.addTest(TestSeleniumOne('test_selenium2'))
47     return suite
48 
49 if __name__ == "__main__":
50     filePath = 'D:\\Report.html'  # 確定生成報告的路徑
51     fp = open(filePath, 'wb')
52     runner = HTMLTestReportCN.HTMLTestRunner(
53         stream=fp,
54         title='簡單Web自動化測試報告',
55         description='簡單Web自動化測試用例結果',    #不傳默認為空
56         tester='wuwei'  # 測試人員名字,不傳默認為QA
57     )
58     runner.run(suite())

  上述測試用例運行結果的測試報告如下: