1. 程式人生 > 其它 >pytest的Hook函式詳解

pytest的Hook函式詳解

Hook函式的定義
Hook函式又稱為鉤子函式,它的作用可以理解成鉤住自己喜歡的東西(在window中,喜歡的東西可理解為訊息),然後對自己喜歡的東西單獨做處理

如:我寫了一個window程式,在程式中我寫了一段程式碼(呼叫window的api來實現鉤子),這段程式碼被系統通過系統呼叫,把其掛入系統中,然後我就可以對我感興趣的訊息進行處理

我寫的這段程式碼包含有一個回撥函式,當有我喜歡的訊息發出時,這個回撥函式就會執行,所以說,鉤子就是指的回撥函式

pytest的Hook函式,修改pytest-html報告
可以修改自定義修改pytest-html報告,修改方法如下:
(1)在專案根目錄新增confest.py

(2)在confest.py通過為標題行實現自定義鉤子函式來修改列,下面的示例在conftest.py指令碼中使用測試函式docstring新增描述(Description)列,新增可排序時間(Time)列,並刪除連結(Link)列:

from datetime import datetime
from py.xml import html
import pytest

@pytest.mark.optionalhook
def pytest_html_results_table_header(cells):
cells.insert(2, html.th('Description'))
cells.insert(
1, html.th('Time', class_='sortable time', col='time')) cells.pop() #刪除最後links列的內容 @pytest.mark.optionalhook def pytest_html_results_table_row(report, cells): cells.insert(2, html.td(report.description)) cells.insert(1, html.td(datetime.utcnow(), class_='col-time')) cells.pop() #刪除最後links列的內容 @pytest.mark.hookwrapper
#也可以用@pytest.hookimpl(hookwrapper=True) 兩者作用相同 def pytest_runtest_makereport(item, call): #此鉤子函式在setup(初始化的操作),call(測試用例執行時),teardown(測試用例執行完畢後的處理)都會執行一次 outcome = yield report = outcome.get_result() report.description = str(item.function.__doc__)

 


參考連結:pytest文件20-pytest-html報告優化(新增Description)
https://www.cnblogs.com/yoyoketang/p/9748718.html

裝飾器pytest.hookimpl(hookwrapper=True)
上面提到一個裝飾器@pytest.hookimpl(hookwrapper=True),它的作用和裝飾器@pytest.mark.hookwrapper是一樣的,當pytest呼叫鉤子函式時,它首先執行鉤子函式裝飾器並傳遞與常規鉤子函式相同的引數(個人理解是當用該裝飾器@pytest.hookimpl(hookwrapper=True)裝飾時,他會把其他常規鉤子函式的引數都傳遞給當前被裝飾的鉤子函式)

在鉤子函式裝飾器的yield處,Pytest將執行下一個鉤子函式實現,並以Result物件的形式,封裝結果或異常資訊的例項的形式將其結果返回到yield處。因此,yield處通常本身不會丟擲異常(除非存在錯誤)

總結如下:
@pytest.hookimpl(hookwrapper=True)裝飾的鉤子函式,有以下兩個作用:
(1)可以獲取到測試用例不同執行階段的結果(setup,call,teardown)
(2)可以獲取鉤子方法的呼叫結果(yield返回一個result物件)和呼叫結果的測試報告(返回一個report物件)

@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport(item, call): #對於給定的測試用例(item)和呼叫步驟(call),返回一個測試報告物件(_pytest.runner.TestReport)
  """
  每個測試用例執行後,製作測試報告
  :param item:測試用例物件
  :param call:測試用例的測試步驟
   執行完常規鉤子函式返回的report報告有個屬性叫report.when
先執行when=’setup’ 返回setup 的執行結果
然後執行when=’call’ 返回call 的執行結果
最後執行when=’teardown’返回teardown 的執行結果
  :return:
  """
  # 獲取常規鉤子方法的呼叫結果,返回一個result物件
  out = yield
  # # 獲取呼叫結果的測試報告,返回一個report物件, report物件的屬性包括when(steup, call, teardown三個值)、nodeid(測試用例的名字)、outcome(用例的執行結果,passed,failed)
  report = out.get_result()
  print(out)
  print(report)
  print(report.when)
  print(report.nodeid)
  print(report.outcome)

 



執行結果:執行三次的原因是此鉤子函式會在測試用例執行的不同階段(setup, call, teardown)都會呼叫一次

 1 testcase/test_getRegionCountry/test_GetRegionCountry.py::test_getRightrequest <pluggy.callers._Result object at 0x0000000004B7D828>
 2 <TestReport 'testcase/test_getRegionCountry/test_GetRegionCountry.py::test_getRightrequest' when='setup' outcome='passed'>
 3 setup
 4 testcase/test_getRegionCountry/test_GetRegionCountry.py::test_getRightrequest
 5 passed
 6 <pluggy.callers._Result object at 0x0000000002FAA748>
 7 <TestReport 'testcase/test_getRegionCountry/test_GetRegionCountry.py::test_getRightrequest' when='call' outcome='passed'>
 8 call
 9 testcase/test_getRegionCountry/test_GetRegionCountry.py::test_getRightrequest
10 passed
11 PASSED<pluggy.callers._Result object at 0x000000000303F5F8>
12 <TestReport 'testcase/test_getRegionCountry/test_GetRegionCountry.py::test_getRightrequest' when='teardown' outcome='passed'>
13 teardown
14 testcase/test_getRegionCountry/test_GetRegionCountry.py::test_getRightrequest
15 passed

 



參考連結
pytest之外掛pytest.hookimpl用法https://www.cnblogs.com/vevian/articles/12631555.html
Hook 方法之 pytest_runtest_makereport:獲取測試用例執行結果
https://blog.csdn.net/waitan2018/article/details/104347519

Hook函式排序/呼叫示例
對於任何給定的鉤子函式規格,可能存在多個實現,因此我們通常將鉤子函式執行視為1:N的函式呼叫,其中N是已註冊函式的數量。有一些方法可以影響鉤子函式實現是在其他之前還是之後,即在N-sized函式列表中的位置:

# Plugin 1
@pytest.hookimpl(tryfirst=True)
def pytest_collection_modifyitems(items):
# will execute as early as possible
...

# Plugin 2
@pytest.hookimpl(trylast=True)
def pytest_collection_modifyitems(items):
# will execute as late as possible
...

# Plugin 3
@pytest.hookimpl(hookwrapper=True)
def pytest_collection_modifyitems(items):
# will execute even before the tryfirst one above!
outcome = yield
# will execute after all non-hookwrappers executed

 


這是執行的順序:

Plugin3的pytest_collection_modifyitems被呼叫直到注入點,因為它是一個鉤子函式裝飾器。
呼叫Plugin1的pytest_collection_modifyitems是因為它標有tryfirst=True。
呼叫Plugin2的pytest_collection_modifyitems因為它被標記trylast=True(但即使沒有這個標記,它也會在Plugin1之後出現)。
外掛3的pytest_collection_modifyitems然後在注入點之後執行程式碼。yield接收一個Result例項,該例項封裝了呼叫非裝飾器的結果。包裝不得修改結果。
以上使用tryfirst,trylast,以及結合hookwrapper=True的示例,它會影響彼此之間hookwrappers的排序

參考連結
Pytest權威教程19-編寫鉤子(Hooks)方法函式
https://www.cnblogs.com/superhin/p/11478007.html

pytest-html官方文件地址
https://pypi.org/project/pytest-html/

其餘參考連結
Pytest官方教程-20-編寫鉤子(hook)方法
https://www.jianshu.com/p/b8178b693f87
pytest進階之html測試報告
https://www.cnblogs.com/linuxchao/p/linuxchao-pytest-report.html
pytest文件20-pytest-html報告優化(新增Description)
https://www.cnblogs.com/yoyoketang/p/9748718.html
————————————————
版權宣告:本文為CSDN博主「神奇的洋子」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/u011035397/article/details/109546814