pytest是一個非常好用的測驗框架,并且這個框架已經非常成熟了,
它簡單靈活,容易上手,支持引數化,也能夠支持簡單的單元測驗和復雜的功能測驗,也是自動化測驗的利器,
我們先來看看如何安裝:在Python環境沒問題的情況下直接pip install pytest即可,進入正題
目錄
命令列引數
vs
maxfail
xdist
reruns
測驗報告
allure
mark標簽
前置后置
fixture
引數化
命名
擴展
命令列引數
vs
先來看一個比較簡單的示例,我們直接從示例入手:
import pytest
def test_01():
print("第一條用例")
class Testcase:
def test_02(self):
print("第二條測驗用例")
注意看我的類名,首字母大寫的!!!這里實際上是不會在控制臺輸出我們的列印資訊的,所以我們還需要改改:
import pytest
def test_01():
print("第一條用例")
class Testcase:
def test_02(self):
print("第二條測驗用例")
if __name__ == '__main__':
pytest.main(["-s","-v","running.py"])
-s是顯示列印資訊,-v顯示詳細的測驗結果,這里你也可以寫到一起去,也就是:
if __name__ == '__main__':
pytest.main(["running.py","-vs"])
除了寫main方法可以輸出結果之外,我們開始控制臺直接碼命令,

可能你會遇到no tests ran in 0.01s這樣的情況,這種情況一般都是目錄下找不到執行檔案,這時候你就需要cd 切換到檔案所在的檔案目錄就好了,執行命令也是大同小異,
pytest running.py -vs
maxfail
當maxfail=1的時候,用例里面出現一個錯誤用例停止運行
接下來我們多寫幾個用例:
def test_01():
print("第一條用例")
assert 0 > 1
def test_04():
print("清安無別事")
class Testcase:
def test_02(self):
print("第二條測驗用例")
def test_03(self):
print("第三條用例")
我是在控制臺碼命令的,所以這里我就不寫main方法去跑了,
pytest running.py -vs --maxfail=1
xdist
pip install --xdist
多執行緒,在用例少的情況下看不出太大的區別,多執行緒要比單執行緒少節省將近一半的時間,也就是說當xdist 為2時,啟用兩個執行緒,比直接pytest跑節省近一半時間,
def test_01():
print("第一條用例")
def test_04():
print("清安無別事")
class Testcase:
def test_02(self):
print("第二條測驗用例")
def test_03(self):
print("第三條用例")
pytest running.py -vs --maxfail=1 -n 2,這里xdist有縮寫,也就是-n,后面的2就是2個執行緒的意思,注意看下方截圖的紅色框框的位置,就是執行緒的名字,

reruns
pip install pytest-rerunfailures
重試運行,當運行出現錯誤的時候,也就是非預期結果的時候我們可以再次運行一次該用例
reruns為2時,重新運行兩次
def test_01():
print("第一條用例")
assert 0>1
def test_04():
print("清安無別事")
class Testcase:
def test_02(self):
print("第二條測驗用例")
def test_03(self):
print("第三條用例")
pytest running.py -vs - n 2 --reruns 2,看下方的截圖,重復運行的兩次,

測驗報告
pytest框架自帶了一個測驗報告生成器,--html=路徑/名稱.html
def test_01():
print("第一條用例")
assert 0>1
def test_04():
print("清安無別事")
class Testcase:
def test_02(self):
print("第二條測驗用例")
def test_03(self):
print("第三條用例")
如果我想將這四個用例生成測驗報告:
pytest running.py -vs - n 2 --reruns 2 --html=report/report.html
在report檔案夾下生成一個report.html報告,這個報告雖然很一般 ,也是不錯了,當然我們也可以生成allure測驗報告,美觀一些,
allure
pip install allure-pytest下載好庫,
pytest running.py -vs --alluredir ../report/xmll
allure generate --clean ../report/xmll -o ./result/html
仔細看你就會發現其實--clean后面接的是運行代碼時-o后面的路徑,因為運行pytest running.py -vs --alluredir ../report/xmll后,檔案下會自行創建一個report檔案,用例運行資訊會存在xmll里面,我們生成報告就需要呼叫里面的資訊,
因為我是控制臺輸出的所以需要這兩行代碼,輸出完后就可以在result檔案下看到一個index.html檔案,就是測驗報告了,如下圖所示:

mark標簽
什么是mark標簽?mark標簽分為內置標簽與外置標簽,可以用來對用例進行管理運行,我們直接看看例子:
def test002():
print('這是一條最優級別的用例')
def test005():
print("skip_reason")
def test003():
print('這是一條嚴重級別的用例')
def test006():
print("006冒煙")
def test004():
print('這是一條較嚴重級別的用例')
上述例子的情況下,與正常情況下無異,這里需要注意:
pytest與unittest不一樣,我test序列號寫的很亂,如果是在unittest中的話肯定就是按數字的順序來執行了,pytest中不分先后,05在04用例的前面,那么就得按這順序來,先運行05用例再04用例,
那么我們給這里加上mark標簽看看:
def test002():
print('這是一條最優級別的用例')
def test005():
print("005冒煙")
@pytest.mark.qingan
def test003():
print('這是一條嚴重級別的用例')
def test006():
print("006冒煙")
@pytest.mark.qinganan
def test004():
print('這是一條較嚴重級別的用例')
猜猜這里運行幾條用例?3條,沒錯,
注意:這里mark標簽是外置標簽,我自己命名的,看看運行結果:
pytest -m qingan test_speack.py -sv這里指定外置標簽的標簽名,不指定就會運行全部的用例,不指定怎么對用例進行管理,

這里還是可以看到只執行了兩條,也就是標簽的那兩條用例,這里對指定用例進行標記運行,
mark標簽會受外界的裝飾器影響嗎?我們來看看,
def func(function):
def fn(*args,**kwargs):
print("this is "+function.__name__)
return function(*args,**kwargs)
return fn
# ----------上面是自己寫的裝飾器--------------
@func
def test002():
print('這是一條最優級別的用例')
# @pytest.mark.skip
def test005():
print("skip_reason")
@pytest.mark.qingan
@func
def test003():
print('這是一條嚴重級別的用例')
def test006():
print("006冒煙")
@pytest.mark.qingan
@func
def test004():
print('這是一條較嚴重級別的用例')
是不會的,也是遵循pytest強大的執行順序來的,
那么看了自定義標簽,看看內置標簽吧:
def func(function):
def fn(*args,**kwargs):
print("this is "+function.__name__)
return function(*args,**kwargs)
return fn
# ----------上面是自己寫的裝飾器--------------
@func
def test002():
print('這是一條最優級別的用例')
@pytest.mark.skip
def test005():
print("skip_reason")
@pytest.mark.qingan
@func
def test003():
print('這是一條嚴重級別的用例')
def test006():
print("006冒煙")
@pytest.mark.qingan
@func
def test004():
print('這是一條較嚴重級別的用例')
我在05用例處添加了一個內置標簽,這里需要注意的是,執行命令不一樣:
pytest test_speack.py -s -rs或者pytest -k qingan test_speack.py -sv

05被跳過了,我們可以更改內置標簽的提示資訊
@pytest.mark.skip(reason='不運行')
def test005():
print("skip_reason")

控制臺就會有這樣的一條資訊可以看到,
這里可以看到自定義標簽與內置標簽處用的運行命令有所不同,不同之處在于一個用了-m一個用了-k,
使用-m的時候我們需要指定自定義標簽,才能跑用例,否則跑不起來,如果用-k即使不指定也是可以跑起來,這樣的一個好處,相信不說你也知道了,控制用例執行,可以更好的執行你想執行的用例,更好的是用于冒煙測驗,
另外還有一個也就是內置標簽判斷,skipif,這是一個怎么樣的標簽呢?
看skip后面帶的if就知道了,可以做一個判斷!條件為真則跳過運行,條件為假則運行用例,
@func
def test002():
print('這是一條最優級別的用例')
@pytest.mark.skipif(1>2,reason='不運行')
def test005():
print("skip_reason")
@pytest.mark.qingan
@func
def test003():
print('這是一條嚴重級別的用例')
def test006():
print("006冒煙")
@pytest.mark.qingan
@func
def test004():
print('這是一條較嚴重級別的用例')
pytest -k test_speack.py -sv我在用例005處寫了一個skipif的判斷,1>2是FALSE,所以此處不跳過,

所以此處為真的條件就不舉例了,此處直接告訴各位答案了,
前置后置
在unittest你肯定看到過setup這一類的函式,看下面的例子
class Testcasse():
"""前置后置"""
def setup(self):
print("1每個用例的前置")
def teardown(self):
print("2每個用例的后置")
def setup_class(self):
print("3所有用例的前置")
def teardown_class(self):
print("4所有用例的后置")
def test_004(self):
print("004")
def test_005(self):
print("005")
其中的順序是怎么樣的呢,是否跟之前說的全部無優先級呢?運行一下就知道了,

這里就很明顯了,優先級是3124,這里別誤會,我在print里面加了數字,說一 這里就這樣簡寫了,下面兩個用例004,005是用于分辨的,不然運行不起來,各位可以自己跑一跑,這與pytest本身的規則有關系,
fixture
這里很容易弄錯寫成fixtrue,所以需要注意一些,怎么用呢?fixture可以實作我們在pytest的用例中調傭其他函式,可以發現我們使用fixture是在被呼叫函式之上添加我們的fixture,看例子:
@pytest.fixture
def login():
print("login")
return "運行用例"
def test_seacher():
print(login) # 回傳的是一個地址
print(f"搜索用戶名{login}")
def test_seacher1(login):
print(login)
print(f"搜索用戶名{login}")
pytest text_fixtrue.py -sv運行起來看看效果:

這樣看就不難理解了,這是一種簡單的距離,看起來像是呼叫,
fixture區別于unnitest的傳統單元測驗(setup/teardown)有顯著改進,
fixture里面有個scope引數可以控制fixture的作用范圍:session>module>class>function
-function:每一個函式或方法都會呼叫
-class:每一個類呼叫一次,一個類中可以有多個方法
-module:每一個.py檔案呼叫一次,該檔案內又有多個function和class
-session:是多個檔案呼叫一次,可以跨.py檔案呼叫,每個.py檔案就是module
這里就需要用到了conftest.py配置了,可以實作資料共享,比如py跨檔案共享前置,另外需要注意的是conftest.py腳本名稱是固定的,不更改名稱,pytest會自動尋找這個檔案,
如果此檔案放到專案的根目錄下就可以全域呼叫了,如果放到某個package下,那就在改package內有效,
在根目錄下這是conftest下的內容:
@pytest.fixture(scope='function')
def openbrowser():
print("打開瀏覽器")
@pytest.fixture(scope='session')
def qingan():
print("我是清安")
這是某個檔案內的demo下的內容,主要看Testcase中的內容:
@pytest.fixture(scope='session')
def login():
print("登錄方法")
# return "瀏覽器"
# 此處當scope等于function時,yield可以作用于全域
yield "類似于teardown,用法可以跟return一樣"
def testSQL(login):
print("鏈接資料庫")
print(login)
return "資料庫連接結果"
@pytest.fixture()
def test01(login):
print("用例1")
class Testcase():
def test02(self,openbrowser):
print("用例2")
def test03(self,qingan):
print("用例3")
我呼叫了conftest下的function跟session引數方法,

這里可以看到,都被呼叫了,當然方法不唯一,用法不唯一,這里做這么一個簡單的介紹,主要看各位怎么個用法,module也可以這樣寫,
接下來我們來看看實際的示例,我打開瀏覽器:demo.py檔案
from selenium import webdriver
# 這里每次都需要打開一次瀏覽器,然后關閉再打開
@pytest.fixture
def fox():
fox1 = webdriver.Firefox()
print("login")
return fox1
def test_seacher(fox):
fox.get("https://baidu.com")
fox.quit()
def test_seacher1(fox):
fox.find_element_by_id('kw').send_keys("pytest")
fox.find_element_by_id('su').click()
fox.quit()
這里是單獨的fixture直接同一檔案下呼叫,打開兩開瀏覽器,有點像unittest中的setup用法,這里的test_seacher1`又再次打開了一次瀏覽器導致不是百度界面無法定位到元素,
那么我們看看session怎么用------conftest.py檔案
import pytest
from selenium import webdriver
@pytest.fixture(scope='session')
def fox():
fox = webdriver.Firefox()
yield fox
demo.py檔案
@pytest.mark.usefixtures('fox')
class TestCase():
def test01(self,fox):
fox.get("https://baidu.com")
print(fox.title)
def test02(self,fox):
fox.find_element_by_id('kw').send_keys("pytest")
fox.find_element_by_id('su').click()
def test03(self,fox):
fox.quit()
這里用到了mark標簽中的usefixtures方法,不用解釋應該也知道了有use的地方是什么意思了吧,使用fixture方法,這里直接引入了conftest中的fox,只打開一次瀏覽器就能往下定位了,是不是很神奇,當然,module也是用在conftest里面,
引數化
有點像資料驅動,可以處理一些測驗資料,簡單的看看它的一個格式情況:
argnames:引數名
argvalues:引數對應值,型別必須為list
datas = [('qingan', '123'),('qingqingan', '123456')]
class TestQingan:
@pytest.mark.parametrize(argnames=['username', 'password'], argvalues=datas)
def testqing01(self, username, password):
# 這里的運行兩個用例
print("處處把歡喜")
print(username, password)
這里會把datas中的資料決議出來:串列中有幾個元組就有幾個對應的資料,

當然,還有一種情況就是會隨機匹配對應的數值,說的比較抽象我們直接看看:
class TestQingan:
@pytest.mark.parametrize("username",["qingan","123456"])
@pytest.mark.parametrize("password",["qingqingan","123456"])
def testqing01(self, username, password):
# 這里的運行兩個用例
print("處處把歡喜")
print(username, password)
如果你這樣寫了,那么pytest會把username跟password中的串列打亂,然后一一匹配:

命名
不知道你是否喜歡pytest的命名規則,如果不喜歡,此處有一好辦法,幫你解決,
跟目錄下創建一個pytest.ini檔案,在里面這樣寫,pytest會自動去識別,往下看會解釋規則
[pytest]
addopts= -s -vv --alluredir=./result/xml
testpaths=../P_pytest/inidemo
python_files=test*.py
python_classes=Qing*
python_functions=qing*
以我上述的例子為例題運行出來的效果也與上述沒有太大的差別,只是更改了名字而已:
class Qingan:
@pytest.mark.parametrize("username",["qingan","123456"])
@pytest.mark.parametrize("password",["qingqingan","123456"])
def qing01(self, username, password):
# 這里的運行兩個用例
print("處處把歡喜")
print(username, password)

好了,下面解釋一下pytest.ini里面的配置規則
[pytest]
addopts= -s -vv --alluredir=./result/xml
addopts= -s -vv --html=./report/test.html
# 這里是檔案運行的目錄../表示上級目錄
# 這里是ALLURE測驗報告資料存放的地方
addopts= -s -vv --alluredir=./result/xml
# 控制臺運行輸出報告 這里指定生成資料的地方 這里指定輸出報告的地方
# allure generate --clean ./result/xml -o ./result/html 這里是在控制臺輸出的,可別搞混了
# 這里是尋找執行用例所存放的檔案
testpaths=../P_pytest/inidemo
# 尋找執行用例,這里可更改用例名稱,不在是test開頭
python_files=test*.py
# 尋找對應的類運行
python_classes=Qing*
# 基于上述條件尋找對應的用例運行
python_functions=qing*
明白的安排上,前面將了一些allure測驗報告的生成,怕你各位沒看懂!
注意:pytest.ini中除了必須的配置引數外,不要存在其他的東西,漢字,字符,注釋等,
擴展
既然生成了allure報告,為何不好好發揮一下呢,我們往報告里加入截圖:
class Qingan:
def qing02(self):
fox = webdriver.Firefox()
try:
fox.get('https://baidu.com')
time.sleep(3)
except Exception as e:
"""點擊錯誤的時候在報告中插入截圖"""
file_path = './img/' + str(int(time.time())) + ".png"
fox.save_screenshot(file_path)
with open(file_path, mode='rb') as file_img:
f = file_img.read()
# 此處的shouye是放在allure報告中的名字
allure.attach(f, 'shouye', allure.attachment_type.PNG)
fox.quit()
代碼給到各位,僅限于借鑒參考!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/303700.html
標籤:其他
上一篇:首批 iPhone 13 用戶直呼太“坑”:?拍照有馬賽克、與 Apple Watch “失聯”、第三方 App 還不能用高刷?
