天天看點

unittest 單元測試架構

作者:我餓了設計師

unittest 單元測試架構

Unittest 單元測試架構簡介

Unittest 是python内置的單元測試架構,具備編寫用例、組織用例、執行用例、功能,可以結合selenium 進行UI自動化測試,也可以結合appium、requests 等子產品做其它自動化測試。

使用unittest 前需要熟悉該架構的五個概念:

test case : 一個完整的測試單元,執行該測試單元可以完成對某一個問題的驗證,完整提現在測試前環境準備(setUp),執行測試代碼(run),一級測試後環境還原(tearDown)‘

test suit :多個測試用例的集合,測試套件或測試計劃;

testLoader : 加載TestCase 到TestSuite 中的,其中loadTestsFrom__() 方法用于尋找TestCase,并建立它們的執行個體,然後添加到TestSuite中。

test runner : 執行多個測試用例,并将測試結果儲存到TestTestResults 執行個體中,包括允許多少測試用例,成功了多少,失敗了多少等資訊;

test fixture : 一個測試用例的初始化準備環境及環境還原,主要是setUp() 和setDown() 方法

Unittest 基礎架構

unittest 基礎使用步驟:

  1. 用import 語句引入unittest 子產品
  2. 讓所執行的測試的類都基礎于TestCase類,可以将TestCase看出是對特定類程序測試的方法的集合
  3. setUp() 方法中進行測試前的初始化工作, teardown() 方法中執行測試後的清理工作,它們都是TestCase 中的方法
  4. 編寫測試的方法最好以test 開頭(可以直接運作)

def test_add(self)、def test_sub(self)等,可以編寫多個測試用例對被測對象進行測試

  1. 在編寫測試方法過程中,使用TestCase class提供的方法測試功能點,比如:assertEqual等
  2. 調用 unittest.main() 方法運作所有以test開頭的方法。

unittest 代碼示例

import unittest

class test_cases(unittest.TestCase): # 繼承TestCase類

def setUp(self): # 測試用例執行之前初始化

print('setUp')

def tearDown(self): # 測試用例執行之後還原、清理

print('tearDown')

def testcase01(self):

print('execute case01')

self.assertEqual(3,3) # 斷言

if __name__ == '__main__':

unittest.main()

unittest 常用斷言介紹:

斷言即進行預期結果和實際結果對比。

assertEqual(a,b) a == b # a,b 是否相等

assertNotEqual(a,b) a != b # a,b 是否不相等

assertTrue(x) bool(x) is True # x 是否為True

assertFalse(x) bool(x) is False # x 是否為False

assertIn(a,b) a in b # a是否包含 b

assertGreater(a,b) a>b # a大于b

assertGreaterEqual(a,b) a>=b # a 大于等于b

assertLess(a,b) a<b # a 小于 b

assertLessEqual(a,b) a<=b # a 小于等于b

可以在斷言最後一個參數中加入自定義的測試失敗資訊,如:

assertEqual(10,20,”10!=20 測試失敗”) 當斷言失敗時,顯示該資訊。

unittest用例執行順序:

當在一個測試類或多個測試子產品下,用例數量較多時,unittest在執行用例(test_xxx)時,并不是從上到下的順序執行,有特定的順序。

unittest架構預設根據ACSII碼的順序加載測試用例,數字與字母的順序為0~9,A~Z,a~z。

對于類來說,class TestAxx 會優先于class TestBxx被執行,對于方法來說,test_aaa()方法會優先于test_bbb()被執行。對于測試目錄與測試檔案來說,unittest同樣時按照這個規則來加載測試用例的。

Unittest 用例執行順序代碼示例:

import unittest

class test_cases_01(unittest.TestCase):

def setUp(self) -> None:

print('setup')

def tearDown(self) -> None:

print('tearDown')

def test_ccc(self):

print('execute test_ccc')

self.assertEqual(3,3)

def test_aaa(self):

print('execute test_aaa')

self.assertEqual(3,3)

if __name__ == '__main__':

unittest.main()

Unittest 控制測試用例執行順序:

如需要unittest自行控制測試方法的執行順序,可以通過如下兩種方法;

方法一:通過addTest()添加用例的順序控制用例執行

if __name__ == '__main__':

suite = unittest.TestSuite()

suite.addTest(test_cases_01('test_ccc'))

suite.addTest(test_cases_01('test_aaa'))

unittest.main(defaultTest='suite')

方法二:順應unittest的預設執行順序,通過設定測試類或者測試方法方法名字來實作。

Unittest 忽略用例:

在執行測試腳本的時候,可能會有某幾條用例本次不想執行,但又不想删也不想注釋,unittest通過忽略部分測試用例不執行的方式,分無條件忽略和有條件忽略,通過裝飾器實作所描述的場景。提供的裝飾器如下:

@unittest.skip(reason): 強制跳轉。reason是跳轉原因

@unittest.skipIf(condition,reason):condition為True的時候跳轉

@unittest.skipUnless(condition,reason):condition為False的時候跳轉

@unittest.expectedFailure:标記該測試預期為失敗,如果該測試方法運作失敗,則該測試不算做失敗。

Unittest忽略用例示例代碼:

import unittest

class test_cases_01(unittest.TestCase):

def setUp(self) -> None:

print('setup')

def tearDown(self) -> None:

print('tearDown')

@unittest.skip('無條件跳過')

def test_ccc(self):

print('execute test_ccc')

self.assertEqual(3, 3)

@unittest.skipIf(True, '條件為真時跳過')

def test_aaa(self):

print('execute test_aaa')

self.assertEqual(3, 3)

@unittest.skipUnless(False, '條件為假跳過')

def test_bbb(self):

print('execute test_bbb')

self.assertEqual(3, 3)

@unittest.expectedFailure # 預期結果為斷言失敗

def test_ddd(self):

print('execute test_ddd')

self.assertEqual(3, 3)

def test_fff(self):

print('execute test_fff')

self.assertEqual(3, 3)

if __name__ == '__main__':

suite = unittest.TestSuite()

suite.addTest(test_cases_01('test_ccc'))

suite.addTest(test_cases_01('test_aaa'))

suite.addTest(test_cases_01('test_bbb'))

suite.addTest(test_cases_01('test_ddd'))

suite.addTest(test_cases_01('test_fff'))

unittest.main(defaultTest='suite')

建構測試套件

在實際項目中,随着項目進度的開展,測試類會越來越多,可是直到現在我們還隻會一個一個單獨運作測試類,這在實際項目實踐中肯定是不可行的,在unittest中可以通過測試套件來解決該問題。

測試套件(Test Suits)是由多個測試用例(Test Case)組成的,當然也可以由多個子套件組成。

在unittest中,把測試用例加載到測試套件的方法由如下方法:

方法一:

用unittest.TestSuite()執行個體化測試套件對象後,内部的addTest() 方法對測試類颞部的測試案例逐一添加:

if __name__ == '__main__':

suite = unittest.TestSuite()

suite.addTest(test_cases_01('test_ccc')) # 增加單個測試用例

suite.addTest(test_cases_01('test_aaa'))

unittest.main(defaultTest='suite')

方式二:

Unitttest提供一個TestLoader類用于自動建立一個測試集并把單個測試放入到測試集中。TestLoader自動運作以test開頭的測試方法。可以通過如下方法加載用例:

if __name__ == '__main__':

# 增加類下的所有用例

suite01 = unittest.TestLoader().loadTestsFromTestCase('TestCase02')

# 增加子產品下所有用例

suite02 = unittest.TestLoader().loadTestsFromModule('test_case_02')

suite02.run()

在導入類及子產品下的測試用例之前,如果用例實在其它子產品,需要先進行import導入操作。

方式三:

用unittest.TestSuite()執行個體化測試套件對象後,内部的addTests()方法可以把多個子測試集合進行整合到一個大的測試集合中

if __name__ == '__main__':

allsuite = unittest.TestSuite() # 增加單個測試用例

testsuite01 = unittest.TestSuite()

testsuite01.addTest('test_dddd')

testsuite01.addTest('test_eee')

testsuite02 = unittest.TestLoader().loadTestsFromModule('TestCases03') # 增加子產品下的所有用例?

allsuite.addTests(testsuite01) # 把testsuite01集合的用例加載到allsuite測試集合

allsuite.addTests(testsuite02) # 把testsuite02 集合的用例加載到allsuite測試集合

unittest.main(defaultTest='allsuite')

方式四:

當測試用例存放在多個不同目錄下,我們能用之氣那把用例加載到測試集合中的方式是不太友善,需要不斷去導入和添加用例子產品,如此可以通過discover()方法實作,實作如下:

Discover(start_dir,pattern = ‘test*.py’,top_level_dir = None)

Start_dir : 要測試的子產品名或測試用例目錄;

Pattern=’test*.py’ :表示用例檔案名的比對原子,例子中比對檔案名以“test”開頭的“.py”檔案,星号“*”表示任意多個字元。

Top_level_dir=None :測試子產品的頂層目錄,如果沒有頂層目錄,預設是None。

該方法通過從指定的開始目錄遞歸到子目錄中查找所有測試子產品,并傳回包含它們的TestSuite對象,隻要與模式比對測試檔案和可導入的子產品名稱才會被加載。

如果一個測試檔案的名稱符合pattern,會自動查找該檔案中派生自TestCase的類包含的test開頭的方法作為測試方法。

代碼示例:

import unittest,os

case_path = os.path.join(os.path.dirname(__file__))

print(case_path)

def get_all_cases():

discover = unittest.defaultTestLoader.discover(case_path,pattern='test*.py',top_level_dir=None) # 加載不同子產品下的用例

suit = unittest.TestSuite()

suit.addTest(discover)

return suit

if __name__ == '__main__':

suite = unittest.TestSuite()

suite = get_all_cases()

unittest.main(defaultTest='suite')

Unittest 生成測試報告

測試報告為測試結果的統計即展示,是自動化測試不可或缺的一部分,利用unittest生成測試報告方式如下:

方式一:

用unittest.main()執行測試集

if __name__ == '__main__':

suite = unittest.TestSuite()

unittest.main() # 執行目前子產品下所有類的測試用例

unittest.main(verbosity=2) # 執行目前子產品下所有類的測試用例

unittest.main(defaultTest='suite') # 執行suite測試集合下所有的測試用例

這裡的verbosity是一個選項,表示測試結果的資訊複雜度,有三個值:

0 (靜默模式) :你隻能獲得總的測試用例數和總的結果,比如100個,失敗20個,成功80個

1 (預設模式) :非常類似靜默模式,隻是再每個成功的用力前面有個“.”,每個失敗的用例前面有個“F”。

2 (詳細模式) :測試結果會顯示每個測試用例的所有相關的資訊

方式二:

使用TextTestRunner 執行測試用例集,TextTestRunner有三個參數,它們都哦有靜默參數:

  1. Verbosity 分别三個級别:0,1,2它們輸出的測試報告詳細程度不同,2 最詳細
  2. Stream 關系着測試報告的位置,如果預設為None的話,測試報告會輸出到控制台
  3. descriptions 測試報告的描述

mport unittest,os

case_path = os.path.join(os.path.dirname(__file__))

print(case_path)

def get_all_cases():

discover = unittest.defaultTestLoader.discover(case_path,pattern='test*.py',top_level_dir=None) # 加載不同子產品下的用例

suit = unittest.TestSuite()

suit.addTest(discover)

return suit

if __name__ == '__main__':

# 方式一:

# suite = unittest.TestSuite()

# suite = get_all_cases()

# unittest.main(defaultTest='suite')

# 方式二:

# suite = unittest.TestSuite()

# unittest.main() # 執行目前子產品下所有類的測試用例

# unittest.main(verbosity=2) # 執行目前子產品下所有類的測試用例

# unittest.main(defaultTest='suite') # 執行suite測試集合下所有的測試用例

# 方式三:

from sample.test_02.test_cases_01 import test_cases_01

suite = unittest.TestSuite()

suite = get_all_cases()

test_runner = unittest.TextTestRunner(stream=None,descriptions=None,verbosity=2)

test_runner = unittest.TextTestRunner(stream=None,descriptions=None,verbosity=0)

with open('test_result.txt','w',encoding='utf-8') as file:

runner = unittest.TextTestRunner(stream=file, descriptions='執行用例的測試報告', verbosity=2)

runner.run(suite)

生成的txt報告:

unittest 單元測試架構

方式三:

使用第三方HTMLRunner 執行用例集,它可以輸出網頁版本測試報告

HTMLTestRunner 是Python标準庫的unittest子產品的一個擴充,在使用該子產品之前要下載下傳HTMLTestRunner.py檔案,并将該檔案儲存在python安裝路徑下的lib檔案夾或者是項目的子包中,在python代碼中通過import HTMLTestRunner導入,即可使用。

import unittest,os

case_path = os.path.join(os.path.dirname(__file__))

print(case_path)

def get_all_cases():

discover = unittest.defaultTestLoader.discover(case_path,pattern='test*.py',top_level_dir=None) # 加載不同子產品下的用例

suit = unittest.TestSuite()

suit.addTest(discover)

return suit

if __name__ == '__main__':

import HTMLTestRunner

suite = unittest.TestSuite()

suite = get_all_cases()

html_obj = open('result.html','w+',encoding='utf-8') # 建立

runner = HTMLTestRunner.HTMLTestRunner(stream=html_obj,

title='測試報告',

description='測試報告')

runner.run(suite)

HTMLTestRunner常用參數:

stream : 配置測試報告要儲存的檔案路徑

title : 測試報告标題

description : 測試報告的描述資訊

生成的簡易的html報告:

unittest 單元測試架構

測試用例資訊在報告中顯示:

一:在測試用例中加上注釋西悉尼,即可在html報告中展現,能更好的展示每個用例的資訊。

import unittest,os

class TestCases03(unittest.TestCase):

'''測試類的詳細資訊'''

def setUp(self) -> None:

print('setUp')

def tearDown(self) -> None:

print('tearDown')

def test_aaa(self):

'''測試用例test_aaa的詳細資訊'''

print('execute test_aaa')

self.assertEqual(3,3)

def test_ccc(self):

'''測試用例test_ccc的詳細資訊'''

print('execute test_ccc')

self.assertEqual(3,3)

def test_dddd(self):

'''測試用例test_dddd的詳細資訊'''

print('execute test_ccc')

self.assertEqual(3,3)

def test_eee(self):

'''測試用例test_eee的詳細資訊'''

print('execute test_eee')

self.assertEqual(3, 3)

unittest 單元測試架構

測試用例資訊在報告中顯示:

二:在測試方法中通過:

self._testMethodName = ‘設定測試用例的名稱’

self._testMethodDoc = ‘設定測試用例詳情’

def test_aaa(self):

'''測試用例test_aaa的詳細資訊'''

self._testMethodName = 'test_aaa'

self._testMethodDoc = '測試用例test_aaa詳細資訊'

print('execute test_aaa')

self.assertEqual(3,3)

生成的報告如下圖:

unittest 單元測試架構

方式四:

使用第三方HTMLTest ReportCN 執行測試用例集,它可以輸出網頁版測試報告。

在使用該子產品之前下載下傳HTMLReportCN.py檔案,并将該檔案儲存在python安裝路徑下的lib檔案夾或項目的子包中,在python代碼中通過

import HTMLTestReportCN 導入,即可使用。

from sample.test_02.comm import HTMLTestReportCN

suite = unittest.TestSuite()

suite = get_all_cases()

report_dir = './html_report/' # 測試報告路徑,必須以 / 結尾

report_path_obj = HTMLTestReportCN.ReportDirectory(report_dir) # 建立測試報告路徑對象

report_path_obj.create_dir('UI 自動化測試_') # 建立測試報告存放目錄

html_path = HTMLTestReportCN.GlobalMsg.get_value('report_path') # 擷取測試報告檔案對象

html_file = open(html_path,'wb') # 建立html測試報告

html_runner = HTMLTestReportCN.HTMLTestRunner(stream=html_file,

title='UI 測試報告',

tester='YangShiYu',

description='20221013')

html_runner.run(suite)

生成的測試報告展示如下:

unittest 單元測試架構

繼續閱讀