天天看點

Python 自動化之 UnitTest 架構實戰

1 unittest 基本用法

1.1 unittest 初體驗

1.2 unittest 自動化實作實戰

2 unittest 結合 ddt(data-driver tests) 自動化

2.1 ddt 中的 data 與 unpack

2.2 ddt 資料驅動

3 yml 檔案的使用

4 unittest 斷言用法

5 unittest.skip()用法

5 unittest測試套件及runner應用

6 unittest+htmltestrunner 自動化實作

unittest 架構是 python 自帶的一個作為單元測試的測試框,相當于 java中的 junit,随着自動化技術的成熟,unittest 成為了測試架構第一選擇,可以完整的結合 selenium、requests 來實作 ul 和接口的自動化,由 unittest 再衍生出 pytest,pytest 可以完美結合 unittest 來實作自動化。

基本應用:

環境搭建,python 中已經直接加載了 unittest 架構,無須額外安裝

四大元件:

a. test fixture:setup(前置條件)、teardown(後置條件),用于初始化測試用例及清理和釋放資源

b. test case:測試用例,通過內建 unttest.testcase,來實作用例的繼承,在 unitfest 中,測試用例都是通過 test 來識别的,測試用例命名 test_xxx

c. test suite:測試套件,也稱之為測試用例集

d. test runner:運作器,一般通過 runner 來調用 suite 去執行測試

unittest 運作機制:通過在 main 函數中,調用 unitest.main() 運作所有内容

本節知識:1. 對 unittest 有直覺感受

講了這麼多,也完全不明白,沒關系,通過執行個體先有個直覺的了解,unittest 是個什麼東西

對上面的程式進行講解:

類的初始化與釋放

def setupclass(cls) -> none 表示類的初始化,在執行測試用例之前執行,隻執行一次,函數參數為 cls 表示這是一個類方法

def teardownclass(cls) -> none 表示類的釋放,在執行測試用例之後執行,隻執行一次

測試用例的初始化與釋放

def setup(self) -> none 用于測試用例的初始化,在每個測試用例之前都會執行,有多少個測試用例,就會執行多少次

def teardown(self) -> none 用于測試用例釋放,在每個測試用例執行之後執行,有多少個測試用例,就會執行多少次

注意:方法 setupclass,teardownclass,setup,def teardown 的方法名是固定的,不能改動,不然架構無法識别

測試用例的定義

測試用例的命名規則為 test_xxx,這樣測試用例就會自動執行

注意:隻有測試用例才會被執行,不以test_xxx 命名的函數是方法,方法是不能被執行的

執行測試用例

通過在 main 函數中,調用 unitest.main() 運作所有内容

運作結果如下:

類的初始化方法 setupclass(cls) 在所有的測試用例之前執行,類的釋放函數 teardownclass(cls) 在所有的測試用例之後執行

測試用例的初始化在每個測試用例之前都會執行,測試用例的釋放在每個測試用例之後都會執行

test_a(self) 和 test_b(self) 是測試用例,運作時被自動執行,add(self, a, b) 是函數,不會被自動執行,test_c(self) 是測試用例,調用了 add 函數,這樣就可以執行 add 函數了。

相信有了上面的例子,已經對unittest 有了一個初步的印象。

下面我們進行一個實戰操作

本節知識:1. 自動化測試減少備援,便于維護,2. ddt資料驅動

自動化測試減少備援,便于維護

有了類的初始化與釋放,測試用例的初始化與釋放,我們可以将多個測試用例中相同的代碼提取出來,減少自動化測試備援,這樣便于維護

下面看這樣一個例子,我們打開谷歌浏覽器,輸入百度網址并進行搜尋,搜尋後關閉浏覽器

上面的案例中,我們将打開谷歌浏覽器,進入百度,放在 setup 中,完成每個測試用例之前的初始化,浏覽器的關閉放在teardown 中,完成測試用例的釋放

在實際測試中,單個測試是需要用多種不同的條件(測試資料)對其進行測試的。

ddt 中最基本的應用;在 class 前定義 @ddt,用于表示要使用 ddt 了,再基于實際的應用。選擇對應的裝飾器來使用即可,說白了,就是一個裝飾器

data 用于設定參數

unpack 用于解析參數

直接看例子比較直覺

運作結果:

可以看到測試用例 def test_1(self, txt) 被執行了四次,data 用于設定參數,将參數依次放入測試用例中進行測試。

我們改變一下設定的參數,将 data 設定的參數改為 ((‘戰狼’, ‘哪吒’), (‘流浪地球’, ‘複仇者聯盟’)),再進行測試,如下所示

可以看到,傳入參數 ((‘戰狼’, ‘哪吒’), (‘流浪地球’, ‘複仇者聯盟’)) 時,将包 (‘戰狼’, ‘哪吒’) 和 (‘流浪地球’, ‘複仇者聯盟’) 作為一個整體,傳遞給測試用例了,如果我們希望将包裡面的資料解開,傳遞給測試用例不同的參數,就需要用到 unpack 進行解包。

加入解包後的代碼如下所示:

執行結果如下:

可以看到,unpack 對每次傳入的包進行解包,例如将 (‘戰狼’, ‘哪吒’) 解包,‘戰狼’ 指派給 txt1,'哪吒’指派給 txt2

上面的例子中,我們将輸入的參數直接固定了,其實也可以通過檔案讀取,讀取結果決定

ddt.txt 檔案中的内如下:

函數 readfile 從檔案中讀取資料,unpack 進行解包

上面從檔案中讀取資料時先讀取檔案,再處理讀取的結果,下面介紹一個直接操作檔案的方法

從 ddt 中導入 file_data,導入 yaml,讀取資料的檔案類型必須為 .yml 類型的檔案。

ddt2.yml 檔案内容如下:

打開浏覽器進入百度查詢的例子中我們發現除了輸入的參數不同,test_1(self) 和 test_2(self) 完全相同,這裡我們就要通過 data 設定參數實作在一個測試用例中輸入不同的參數

運作結果,谷歌浏覽器被打開三次,進入百度,分别輸入 ‘戰狼’, ‘哪吒’, ‘流浪地球’,每次浏覽器關閉之後,才打開下一次,再進行搜尋

上面的例子中,我們将輸入的參數直接固定了,其實也可以通過檔案讀取,決定進入哪一個 url 和輸入的參數

fortest3.txt 檔案中的内容如下:

分析:

readfile() 函數打開檔案,讀取檔案的每一行,按逗号 ‘,’ 劃分關鍵字,

unpack 用于解析參數,ddt 對于資料的解析方式為,解析一個,傳參一個,是以函數中 url 和 txt 的參數順序不能調換。

運作結果,谷歌浏覽器被打開兩次,進入百度,分别輸入 ‘戰狼’, ‘哪吒’,每次浏覽器關閉之後,才打開下一次,再進行搜尋

file_data 是 ddt 中用于讀取 yml 檔案的裝飾器

這個插入一個小插曲,上面提到了 yml 檔案,這裡就簡單講解一下 yml 檔案怎麼使用。

從yml 檔案中直接讀取資料可以生成字典,清單等,yml 檔案由一定的格式,我們通過執行個體來說明,yml_test.py 從 a.yml 檔案中讀取檔案并列印出來。

yml_test.py

a.yml 檔案中的内容如下所示,冒号代表字典,字典結構可以嵌套,也可以生成清單,具體格式參考下面的 a.yml 檔案。

a.yml

列印的結果如下所示,生成四個字典元素,第三個字典元素為嵌套字典結構,第四個字典對應的 value 為清單。

如果将 a.yml 檔案中的資料改為如下結構,則生成一個純清單,列印的結果如下所示。

有了 yml 檔案,我們就可以将測試資料放到 yml 檔案中,從檔案中擷取參數,傳入測試函數,完成測試。還是通過例子來講解,yml_test2.yml 中是一個清單,每個清單元素是一個字典,字典中有兩個元素,name 和 age,使用 file_data 直接可以将 yml_test2.yml 傳入測試用例中。

read_yml2.py

read_yml2_data.yml

在 unittest中,testcase 已經提供有封裝好的斷言方法進行斷言校驗。

斷言:用于校驗實際結果與預期結果是否匹型,在斷言的内容選擇上,是有要求的。

斷言強調的是對于整個測試流程的結果進行判斷,是以斷言的内容是極為核心的。

上面的代碼

Python 自動化之 UnitTest 架構實戰

可以看到第一個例子執行正确,後面的例子,執行結果和預期不一緻,傳回 notequal,左側的日志可以看到第一個用例執行成功,後面兩個例子執行失敗。

unittest 架構的 testcase 類提供以下方法用于測試結果的判斷

方法

檢查

assertequal(a, b)

a ==b

assertnotequal(a, b)

a !=b

asserttrue(x)

bool(x) is true

assertfalse(x)

bool(x) is false

assertis(a, b)

a is b

assertisnot(a, b)

a is not b

assertisnone(x)

x is none

assertisnotnone(x)

x is not none

assertin(a, b)

a in b

assertnotin(a, b)

a not in b

assertisinstance(a, b)

isinstance(a,b)

assertnotisinstance(a, b)

not isinstance(a,b)

假設我們有很多測試用例,有些我們需要執行,有些我們不想執行,不想執行的測試用例如何才能不執行呢,這就需要用到 skip。

skip用法:

在 case 中,對于不需要運作的用例或者特定條件下不執行的用例,可以應用 skip() 來實作有條件執行,或者絕對性跳過,用于對指定用例進行不執行操作

skip通過裝飾器進行使用

還是通過案例進行講解,下面有 6 個測試用例,2-5測試用例被屏蔽了,使用的方法不同,

@unittest.skip(“xxx”)是無條件跳過,xxx為跳過的理由

unittest.skipif(1 < 2, ‘xxx’),條件為 true 時跳過

@unittest.skipunless(1 > 2, ‘xxx’),條件為 false 時跳過,和 skipif 更好相反

@unittest.expectedfailure,如果用例執行失敗,則不計入失敗的case數中

直接看例子更加直覺

skip_t.py

執行結果如下,可以看到,test_2,test_3,test_4 跳過,test_5執行失敗,但是不計入case數中

Python 自動化之 UnitTest 架構實戰

測試套件 suite 作用:

用于給測試用例進行排序

管理測試用例

通過例子講解最容易了解,看一個最簡單的例子,下面的代碼中有五個測試用例,程式運作的結果和測試用例在代碼中位置是沒有關系的,結果永遠列印 1 2 3 4 5,這是因為測試用例的執行順序預設是按照字典順序執行的,如何才能控制測試用例的執行順序呢,這就需要使用測試套件了。

suite_case.py

再建一個py 檔案

for_suite.py

我們首先建立一個測試套件,然後向測試套件中添加測試用例,最後建立 texttestrunner 對象,調用 run 函數運作測試用例。這樣我們不僅可以控制測試用例的執行順序,還可以控制運作哪個測試用例。

結果如下:

上面的方法每次添加測試用例都需要調用 addtest 函數,能不能一次添加多個測試用例呢,可以的,将測試用例寫成一個清單,通過addtests 函數可以一次添加多個測試用例

如果測試用例非常多,或者有多個檔案中的測試用例都需要測試,這樣添加也不是很友善,我們好可以按照檔案路徑,将該路徑下需要測試的檔案添加進測試套件中

還可以執行類的名字,執行該類下面所有的測試用例,使用 loadtestsfromname 函數或者 loadtestsfromtestcase 都可以,案例如下:

通過 htmltestrunner 我們可以将測試結果生成 html 檔案,通過網頁端進行檢視。步驟如下:

1. 導入環境

下載下傳 htmltestrunner.py 檔案,下載下傳位址

Python 自動化之 UnitTest 架構實戰

點進入htmltestrunner.py,右鍵另存為就可以下載下傳到本地。

下載下傳後,把htmltestrunner.py 檔案複制到 python 安裝路徑下的 lib 檔案夾中(我的安裝路徑是:c:\users\administrator\appdata\local\programs\python\python38\lib)。在python3中用htmltestrunner.py 報 importerror“:no module named 'stringio’解決辦法,原因是官網的是python2文法寫的,看官手動把官網的 htmltestrunner.py 改成 python3 的文法。

修改内容:

第94行,将import stringio修改成import io

第539行,将self.outputbuffer = stringio.stringio()修改成self.outputbuffer = io.stringio()

第642行,将if not rmap.has_key(cls):修改成if not cls in rmap:

第631行,将print >> sys.stderr, ‘\ntime elapsed: %s’ % (self.stoptime-self.starttime)修改成print(sys.stderr, ‘\ntime elapsed: %s’ % (self.stoptime-self.starttime))

第766行,将uo = o.decode(‘latin-1’)修改成uo = e

第772行,将ue = e.decode(‘latin-1’)修改成ue = e

2. 導包

from htmltestrunner import htmltestrunner

下面就通過案例進行示範

suite_case.py 檔案

create_html_res.py

運作 就會成成 report.html 檔案,浏覽器打開該檔案,如下所示:

Python 自動化之 UnitTest 架構實戰

這樣就生成一個比較直覺的測試報告