在Python的編程語言中,單元測試框架主要是pytest,unittest,和nose,其中應用最廣泛的是unittest和pytest測試框架,
unittest測試框架是內置的模塊,安裝完Python的解釋器后,就可以直接導入使用,但是使用它的時候必須是繼承TestCase
類,才可以調用里面的方法,但是缺陷也是很明顯的,它只能應用於面向對象的編程方式,無法應用於函數式的編程方式,
Python語言它的優勢的是可以是面向對象的編程方式,也可以是函數式的編程方式。pytest就顯得自由,它把每一個以test_
開頭或者是_test結尾的都看成是一個測試對象,同時它的斷言是Python的原生斷言assert,這樣使用起來更加的自由,只要
編寫的不管是模塊還是類,符合它的要求,都是可以執行的。但是前提是需要安裝pytest,它是屬於第三方的庫,安裝的命
令為:
pip install pytest
在這里先寫一個函數的測試代碼,來說明pytest的應用,創建f.py的模塊,在里面編寫以test開頭的測試代碼,然后在該目錄
下執行pytest,發現測試代碼並沒有執行,見如下截圖:
為什么測試代碼沒有執行了?這是因為在pytest中,它會首先尋找以test_開頭或者以_test結尾的測試模塊,然后執行模塊里面
以test_開頭或者是以_test結尾的測試代碼,這里依據這個要去,編寫測試模塊,如下:
再次執行pytest,就會看到模塊里面的測試代碼都已執行,見如下的截圖信息:
當然也查看詳細的信息,使用到的命令為:pytest -v 就會顯示出詳細的執行信息,如下圖所示:
在詳細的信息中,會顯示出執行了那個模塊中的那個具體的測試用例,再完善下模塊中的測試用例,執行多少個,在詳細的信息中它都會
顯示出來,見完善后執行的截圖信息,如下圖所示:
在一個項目文件中,或者說是一個測試的包下面,會有很多的測試模塊文件,但是並不是所有的測試模塊文件需要執行,只是想執行某一個模塊
文件,那么就只需要在執行的時候指定這個文件就可以了,執行的命令為:pytest -v test_xunit_002.py,見執行后的結果截圖信息:
見如上的截圖信息,就只顯示了test_xunit_002.py模塊的測試代碼,並沒有執行另外一個模塊的測試用例。
下面繼續看Pytest中對測試用例執行結果的顯示,如果是正確的顯示passwd,也會使用.來表示,如果是錯誤的,也就是執行失敗的,使用F
來表示,也就是FAILED,完善test_xunit_0002.py模塊的代碼,見源碼:
#!/usr/bin/env python # -*-coding:utf-8 -*- def test_001(): assert 1==1 def test_002(): assert 2==3
見執行后正確的和錯誤的信息的表示,見如下的截圖信息:
在執行結果中會顯示出錯誤的詳細信息,以及成功的個數和失敗的個數。
在pytest框架中,如果沒有指定目錄,它默認是會搜索一個項目下所有可執行的測試模塊以及測試模塊里面的測試用例來進行的,
並不在乎測試用例是在哪個package那個模塊的,這樣的一個過程成為“測試搜索”,只要符合它的規則的它都是會被執行的。在這里,
增加幾個包,在包里面增加幾個測試模塊,見目錄結構的設計:
再次使用pytest -v來進行執行,來看“測試搜索”的過程,見執行的截圖,如下圖所示 :
依據如上的結果信息,pytest測試搜索的規則為:
-
-
測試函數或者測試類方法應該當是test開頭或者是test為結尾
-
測試類應當命名為Test<SomeThing>
下來依據案例繼續看執行單個測試用例的文件,主要分為這么幾個場景,第一個場景是執行某一個模塊下的某一個測試用例,第二個
場景是執行某個模塊下某一分類的測試用例,先來看第一個場景,指定模塊下具體的測試用例,見執行的命令:
如果某一個測試用例名稱是唯一的,或者說是某一些分類,那么就可以使用命令行的-k,以及--collect-ony,-k允許使用
表達式指定希望運行的測試用例,或者多個前綴或者是后綴的測試用例名稱相同,--collect-only主要的應用於篩選,見模塊
的源碼:
#!/usr/bin/env python # -*-coding:utf-8 -*- import pytest def test_001(): pass def test_login_001(): pass def test_login_002(): pass def test_logout_001(): pass def test_logout_002(): pass
當然也可以顯示出執行的詳細的信息:
-m是可以很快速到找到測試類別的分組,比如登錄模塊是一部分的測試用例,退出是一部分的測試用例,這里我們還是以開放平台
為案例,也就是說在一個測試模塊中 ,有很多的測試用例,但是只是想執行openapi的測試用例,見案例代碼:
#!/usr/bin/env python # -*-coding:utf-8 -*- import pytest def test_001(): pass def test_login_001(): pass def test_login_002(): pass def test_logout_001(): pass def test_logout_002(): pass @pytest.mark.openapi def test_open_api_001(): pass @pytest.mark.openapi def test_open_api_002(): pass
這里實現只是單純的執行openapi的測試用例,其它的測試模塊就不再執行了,執行的命令是:pytest -m openapi,見執行后的
結果截圖:
見執行的詳細信息:
在實際的測試場景中,一般性的我們希望不管測試用例執行失敗也好成功也好,都希望測試用例能夠正常的執行,但是也有
一種場景是執行的時候遇到測試用例執行失敗,就立刻停止,這里會使用到的命令是-x,見案例代碼:
#!/usr/bin/env python # -*-coding:utf-8 -*- def test_001(): assert 1==1 def test_002(): assert 1+1==1 def test_003(): assert 2+2==4
我們希望測試用例執行失敗,就立刻停止,執行的命令為:pytest -x
執行到第二個測試用例,由於斷言失敗,所以測試用例再沒有繼續執行。這是符合我們的預期結果的。當然也可以指定最大失敗的次數,
它的命令為:--maxfail=參數,參數也就是指的是最大的失敗次數。繼續執行,執行的命令為:pytest --mailfail=參數
上面指的是最大失敗的次數是0,所以也就等於不管是否失敗,都執行所有的測試用例。這個需求相對來說使用的還是比較少,一般的來說
我們都還是希望所有的測試用例執行,到最后再說具體結果的事,失敗的當然再具體定位和分析,然后得出比較客觀的結論報告。
--tb=no是關閉錯誤信息,--tb=short是輸出assert錯誤的信息,--tb=line是一行輸出所有的所有,具體依據如下的截圖信息來看這三個的區別
和它的應用場景,第一個場景是有錯誤,但是不顯示錯誤的信息,執行的命令是:pytest --tb=no
第二個場景是有錯誤就只輸出assert的這一行的信息,執行的命令為:pytest --tb=short
第三場景是顯示錯誤信息,並且顯示在一行的內容,執行的命令為:pytest --tb=line,如下圖所示:
--lf命令值的是執行測試用例失敗后,希望能夠定位到該測試用例並且重新執行,它的好處是能夠很快速的找到失敗的測試用例
見案例的源碼:
#!/usr/bin/env python # -*-coding:utf-8 -*- def test_001(): assert 1==1 def test_002(): assert 1+1==1 def test_003(): assert 2+2==4
中間的測試用例斷言它是存在問題,但是我們希望能夠很快速的定位到,執行的命令為:pytest --lf,見輸出結果截圖:
顯示出第二個測試用例失敗,很快速的定位到了,並且顯示出了斷言的失敗信息。
--ff是執行完剩余的測試用例,是一個很奇怪的解釋,是不是意味着執行終止了,然后由它負責執行完剩余的測試用例了,是否和-x命令
沖突了,執行的命令為:pytest --ff
-v就是很簡單了,打印出很詳細的信息,-q與-v是相反的,就是打印出簡單的信息,見執行的命令:
如上可以看到打印的信息確實很簡單的,但是有個好處是失敗的測試用例它還是顯示出了很詳細的信息的。這點我覺得特別的好。
- --duration是統計出那些測試用例執行速度慢,這點在接口測試特別的好用,可以看到那個接口請求響應慢,默認是0,耗時從
長到短依次排序顯示,見案例的源碼,同樣的網絡環境測試那個網站訪問速度快。
#!/usr/bin/env python # -*-coding:utf-8 -*- import requests def test_get_page_baidu(url='http://www.baidu.com/'): r=requests.get(url=url) assert r.status_code==200 def test_get_page_taobao(url='http://www.taobao.com/'): r=requests.get(url=url) assert r.status_code==200 def test_get_page_qq(url='http://www.qq.com/'): r=requests.get(url=url) assert r.status_code==200
執行的命令為:pytest --duration=0,見執行后的命令信息:
真的是沒有對比就沒有傷害,有了對比傷害也就出來了,百度的耗時是最長是,淘寶是耗時是最短的。結果是那么的讓人不可思議的。
感謝您關注我的文章,您也可掃描二維碼關注我的公眾號和購買我的Python接口自動化測試實戰視屏課程。