pytest接口自动化测试框架 | 为什么要做pytest插件的二次开发
視頻來源:B站《冒死上傳!pytest接口自動化測試框架(基礎理論到項目實戰及二次開發)教學視頻【軟件測試】》
一邊學習一邊整理老師的課程內容及試驗筆記,并與大家分享,侵權即刪,謝謝支持!
附上匯總貼:pytest接口自動化測試框架 | 匯總_COCOgsta的博客-CSDN博客
【conftest、fixture】
conftest也是pytest特有的本地測試配置文件,既可以用來設置項目級的fixture,也可以用來導入外部插件,還可以指定鉤子函數。conftest.py文件名稱是固定的,pytest會自動設別該文件,只作用在它的目錄以及子目錄。
通過裝飾器@pytest.fixture來告訴pytest某個特定的函數是一個fixture,然后用例可以直接把fixture當參數來調用
【pytest可以通過Hook函數(pytest_runtest_makereport)獲取用例執行的結果】
源碼:
def pytest_runtest_makereport(item: Item, call: CallInfo[None]) -> TestReport:return TestReport.from_item_and_call(item, call)這里的item是測試用例,call是測試步驟,具體執行過程如下:
*先執行when="setup"返回setup的執行結果
*再執行when="call"返回call的執行結果
*最后執行when="teardown"返回teardown的執行結果
鉤子函數=HOOK函數=海盜船長的鉤子
conftest.py
import pytest"""hook裝飾器明天,今天先看他的運行過程 """@pytest.hookimpl(hookwrapper=True, tryfirst=True) def pytest_runtest_makereport(item, call):print('-------------------------------')# 獲取常規的鉤子方法的調用結果,返回一個result對象out = yieldprint('用例的執行結果', out)# 獲取調用結果的測試報告,返回一個report對象,report對象的屬性# 包括when(setup, call, teardown三個值)、nodeid(測試用例的名字)、# outcome(用例執行的結果 passed, failed)report = out.get_result()print('測試報告: %s' % report)print('步驟:%s' % report.when)print('nodeid: %s' % report.nodeid)# 打印函數注釋信息print('description: %s' % str(item.function.__doc__))print('運行結果: %s' % report.outcome)test_case01.py
import pytestdef test_01():""" 用例描述:展昭的用例"""print("用例運行時》》》》》")print("我是展昭")print("用例運行時》》》》》")if __name__ == '__main__':pytest.main(['-s'])運行結果:
從運行結果可以看出,運行用例的過程會經歷三個階段:setup-call-teardown,每個階段都會返回result對象和TestReport對象,以及對象屬性
通過鉤子函數pytest_runtest_makereport可以捕捉到用例執行中的相關數據,這些數據就是我們用來對pytest-html測試報告插件二次開發的基礎。
【setup-call-teardown 3個環節失敗的影響】
fixture實現項目級的前置后置
scope=session這個fixture這個項目只會啟動一次,一般用來做項目級的環境的初始化和清理操作
autouse=True代表自動運行,不需要用例主動去調用
setup失敗情況
當setup執行失敗了,setup的執行結果failed,后面的call用例不會再執行,teardown還是會執行
此時,用例狀態是error,也就是用例call都還沒開始執行,就異常了
call失敗情況
setup正常執行,但是測試用例call失敗了,運行結果是failed
teardown失敗情況
setup正常執行,測試用例call正常執行,teardown失敗了
運行結果:1 passed,1 error
只取call的結果
如果保證setup和teardown不報錯情況,只關注測試用例本身的運行結果,可以加個判斷:
if report.when == "call"
conftest.py
import pytest"""hook裝飾器明天,今天先看他的運行過程 """@pytest.hookimpl(hookwrapper=True, tryfirst=True) def pytest_runtest_makereport(item, call):print('-------------------------------')# 獲取常規的鉤子方法的調用結果,返回一個result對象out = yieldprint('用例的執行結果', out)# 獲取調用結果的測試報告,返回一個report對象,report對象的屬性# 包括when(setup, call, teardown三個值)、nodeid(測試用例的名字)、# outcome(用例執行的結果 passed, failed)report = out.get_result()# 只關注用例本身結果if report.when == "call":print('測試報告: %s' % report)print('步驟:%s' % report.when)print('nodeid: %s' % report.nodeid)# 打印函數注釋信息print('description: %s' % str(item.function.__doc__))print('運行結果: %s' % report.outcome)@pytest.fixture(scope="session", autouse=True) def fix_a():print("setup 前置操作")# print("setup操作失敗")yieldprint("teardown 后置操作 ")# assert 1==2鉤子函數:
1)是個函數,在系統消息觸發時被系統調用
2)不是用戶自己觸發的
3)使用時直接編寫函數體
4)鉤子函數的名稱是確定的,當系統消息觸發、自動會調用
例如:pytest_runtest_makereport
插件與Hook函數的關系:
插件就是用1個或者多個Hook函數,也就是鉤子函數構成的。如果要編寫新的插件,或者是改進現有插件,都必須通過hook函數來進行。所以想掌握Pytest插件二次開發,必須搞定Hook函數。
官網API地址:
https://docs.pytest.org/en/latest/reference/reference.html?highlight=hooks#hooks
5.python的yield的用法詳解
yield:return + generator的一部分
PS:帶yield的函數才是真正的生成器
"""1. 程序開始執行以后,因為test函數中有yield關鍵字,所以test函數并不會真的執行,而是先得到一個生成器g(相當于一個對象)2. 直到調用next方法,test函數才正式開始執行,先執行test函數中的print方法,然后進入while循環3. 程序遇到yield關鍵字,然后把yield想成return,return一個8以后,程序停止,并沒有執行賦值給a的操作,此時next(g)語句執行完成,所以輸出的前兩行(第一個是while上面的print函數,第二個是return出的結果)4.程序執行print("*********************")5.又開始執行下面的print(next(g)),這個時候和上面那個差不多,不過不同的是,這個時候是從剛才那個next程序停止的地方開始執行的,也就是要執行的a的賦值操作,這個時候要注意,這個時候賦值操作的右邊是沒有值的(因為剛才那個是return出去了,并沒有給賦值操作的左邊傳參數),所以這個時候,a賦值是None,所以接著下面輸出的就是a:None6.程序會繼續在while里執行,又一次碰到yield,這個時候同樣return 出8,然后程序停止,print函數輸出的8就是這次return出的8"""def tes():print("begin....")while True:a = yield 8print("a:", a)g = tes() print(next(g)) print("**************************") print(next(g))運行結果:
C:\Users\guoliang\AppData\Local\Programs\Python\Python36\python.exe D:/SynologyDrive/SourceCode/pytest/apitest/test_yield/test.py begin.... 8 ************************** a: None 8Process finished with exit code 0總結:yield和return的關系和區別,帶yield的函數是一個生成器,而不是一個函數了。這個生成器有一個函數就是next函數,next就相當于“下一步”生成哪個數, 這一次的next開始的地方是接著上一次next停止的地方執行的,所以調用next的時候是,生成器,并不會從test函數開始執行,只是接著上一步停止的地方開始,然后遇到yield后,return出要生成的數,此步就結束。
生成器的send函數
"""1. 程序開始執行以后,因為test函數中有yield關鍵字,所以test函數并不會真的執行,而是先得到一個生成器g(相當于一個對象)2. 直到調用next方法,test函數才正式開始執行,先執行test函數中的print方法,然后進入while循環3. 程序遇到yield關鍵字,然后把yield想成return,return一個8以后,程序停止,并沒有執行賦值給a的操作,此時next(g)語句執行完成,所以輸出的前兩行(第一個是while上面的print函數,第二個是return出的結果)4.程序執行print("*********************")5.又開始執行下面的print(next(g)),這個時候和上面那個差不多,不過不同的是,這個時候是從剛才那個next程序停止的地方開始執行的,也就是要執行的a的賦值操作,這個時候要注意,這個時候賦值操作的右邊是沒有值的(因為剛才那個是return出去了,并沒有給賦值操作的左邊傳參數),所以這個時候,a賦值是None,所以接著下面輸出的就是a:None6.程序會繼續在while里執行,又一次碰到yield,這個時候同樣return 出8,然后程序停止,print函數輸出的8就是這次return出的8""" """7.程序執行g.send(7),程序會從yield關鍵字那一行繼續往下運行,send會把7這個值賦給變量a8.由于send方法中包含next()方法,所以程序會繼續向下運行執行print方法。然后再次進入while循環9.程序執行再次遇到yield關鍵字,yield會返回后面的值,程序再次暫停,直到再次調用next方法或者send方法 """def tes():print("begin....")while True:a = yield 8print("a:", a)g = tes() print(next(g)) print("**************************") print(g.send(7))運行結果:
C:\Users\guoliang\AppData\Local\Programs\Python\Python36\python.exe D:/SynologyDrive/SourceCode/pytest/apitest/test_yield/test.py begin.... 8 ************************** a: 7 8Process finished with exit code 0為什么用yield?
例子:取0,1,2,3,....,1000
節省內存,python3中range也改為了class(迭代器),不是一次性把所有數據都裝到內存中
conftest中的yield
總結
以上是生活随笔為你收集整理的pytest接口自动化测试框架 | 为什么要做pytest插件的二次开发的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python安装失败0x80070005
- 下一篇: Unity 多点触控 禁用与启用