鉤子 【pytest官方文檔】解讀-插件開發之hooks 函數( 二 )


為啥用pytest_sessionstart這個hook函數 , 因為通過查看官方API文檔里的介紹 , 發現這個鉤子函數是在創建Session對象之后 , 且在執行收集和進入運行測試循環之前調用 , 所以很適合用在這里 。
所以直接重寫這個hook函數來實現我們定義的功能 。
2. hook函數中的 firstresult示例中使用hook函數pytest_runtest_makereport , 同樣通過查看官方API介紹 , 它的作用是為測試用例的每個setup運行tearDown階段創建TestReport 。而插件要做的事情 , 就是要在用例執行后獲取到狀態 , 若是失敗就存放到本地txt文件 。
當查看hook規范時候 , 發現一個裝飾器參數firstresult=True

鉤子 【pytest官方文檔】解讀-插件開發之hooks 函數

文章插圖
由于在大多數情況下 , 調用hook函數可能還會觸發調用多個hook , 所以最后的結果會是包含所調用鉤子函數的非none結果
firstresult=True時 , 調用鉤子函數時只要有第一個返回非none結果 , 就會將該結果作為整個鉤子調用的結果 。在這種情況下 , 將不會調用其余鉤子函數 。
3. hook函數中的 hookwrapper回到插件代碼本身 , 也用到了一個參數hookwrapper=True
鉤子 【pytest官方文檔】解讀-插件開發之hooks 函數

文章插圖
默認情況下 , 我們之間重寫hook函數來徹底改變它要做的事情 , 就像插件代碼里第一個hook函數pytest_sessionstart一樣 。
hookwrapper=True時 , 等于是我們實現了一個hook函數的包裝器 。鉤子包裝器是一個生成器函數 , 它只產生一次 。
當 pytest 調用鉤子時 , 首先執行鉤子包裝器 , 并像常規鉤子一樣傳遞相同的參數 。
yield關鍵字大家都熟悉了 , 當代碼執行到這里的時候會暫停一下 , 繼續執行下一個鉤子 , 并且會把所有的結果或者異常封裝成一個result對象返回到yield這里 。
鉤子包裝器本身并不返回結果 , 只是在實際的鉤子實現的外面做一些其他的事情 。
我們的插件功能其實也并不是要修改這個鉤子本身測試報告的內容 , 所以就直接通過hookwrapper=True將我們的pytest_runtest_makereport寫成一個包裝好的鉤子 。
接下來就是具體功能的代碼 , 判斷當用例測試結果是fail , 就寫到本地文件中 。
運行運行一下測試用例 , 看下我們插件的執行情況 。
鉤子 【pytest官方文檔】解讀-插件開發之hooks 函數

文章插圖
查看下failures.txt內容 , 結果正確 。
鉤子 【pytest官方文檔】解讀-插件開發之hooks 函數

文章插圖
四、鉤子函數排序/調用示例存在這樣的情況 , 對于同一個鉤子規范 , 可能會存在多個實現 。這種情況下可以使用參數tryfirsttrylast來影響鉤子的調用順序 。
# Plugin 1@pytest.hookimpl(tryfirst=True)def pytest_collection_modifyitems(items):# 盡可能早的執行...# Plugin 2@pytest.hookimpl(trylast=True)def pytest_collection_modifyitems(items):# 盡可能晚的執行...# Plugin 3@pytest.hookimpl(hookwrapper=True)def pytest_collection_modifyitems(items):# 會在上面的 tryfirst 之前執行outcome = yield# 在執行所有非鉤子包裝器之后執行

經驗總結擴展閱讀