Pytest官方教程-20-編寫(xiě)鉤子(hook)方法

目錄:

  1. 安裝及入門
  2. 使用和調(diào)用方法
  3. 原有TestSuite使用方法
  4. 斷言的編寫(xiě)和報(bào)告
  5. Pytest fixtures:清晰 模塊化 易擴(kuò)展
  6. 使用Marks標(biāo)記測(cè)試用例
  7. Monkeypatching/對(duì)模塊和環(huán)境進(jìn)行Mock
  8. 使用tmp目錄和文件
  9. 捕獲stdout及stderr輸出
  10. 捕獲警告信息
  11. 模塊及測(cè)試文件中集成doctest測(cè)試
  12. skip及xfail: 處理不能成功的測(cè)試用例
  13. Fixture方法及測(cè)試用例的參數(shù)化
  14. 緩存: 使用跨執(zhí)行狀態(tài)
  15. unittest.TestCase支持
  16. 運(yùn)行Nose用例
  17. 經(jīng)典xUnit風(fēng)格的setup/teardown
  18. 安裝和使用插件
  19. 插件編寫(xiě)
  20. 編寫(xiě)鉤子(hook)方法
  21. 運(yùn)行日志
  22. API參考
    1. 方法(Functions)
    2. 標(biāo)記(Marks)
    3. 鉤子(Hooks)
    4. 裝置(Fixtures)
    5. 對(duì)象(Objects)
    6. 特殊變量(Special Variables)
    7. 環(huán)境變量(Environment Variables)
    8. 配置選項(xiàng)(Configuration Options)
  23. 優(yōu)質(zhì)集成實(shí)踐
  24. 片狀測(cè)試
  25. Pytest導(dǎo)入機(jī)制及sys.path/PYTHONPATH
  26. 配置選項(xiàng)
  27. 示例及自定義技巧
  28. Bash自動(dòng)補(bǔ)全設(shè)置

編寫(xiě)鉤子(hook)方法

鉤子(hook)方法驗(yàn)證和執(zhí)行

pytest為任何給定的鉤子(hook)規(guī)范調(diào)用已注冊(cè)插件的鉤子(hook)方法。讓我們看一下鉤子(hook)的典型鉤子(hook)方法,pytest在收集完所有測(cè)試項(xiàng)目后調(diào)用。pytest_collection_modifyitems(session, config,items)

當(dāng)我們pytest_collection_modifyitems在插件中實(shí)現(xiàn)一個(gè)方法時(shí),pytest將在注冊(cè)期間驗(yàn)證你是否使用了與規(guī)范匹配的參數(shù)名稱,如果沒(méi)有則拯救。

讓我們看一下可能的實(shí)現(xiàn):

def pytest_collection_modifyitems(config, items):
    # called after collection is completed
    # you can modify the ``items`` list
    ...

這里,pytest將傳入config(pytest配置對(duì)象)和items(收集的測(cè)試項(xiàng)列表),但不會(huì)傳入session參數(shù),因?yàn)槲覀儧](méi)有在方法簽名中列出它。這種動(dòng)態(tài)的“修剪”參數(shù)允許pytest“未來(lái)兼容”:我們可以引入新的鉤子(hook)命名參數(shù)而不破壞現(xiàn)有鉤子(hook)實(shí)現(xiàn)的簽名。這是pytest插件的一般長(zhǎng)期兼容性的原因之一。

請(qǐng)注意,除了pytest_runtest_*不允許引發(fā)異常之外的鉤子(hook)方法。這樣做會(huì)打破pytest運(yùn)行。

firstresult:首先停止非無(wú)結(jié)果

大多數(shù)對(duì)pytest鉤子(hook)的調(diào)用都會(huì)產(chǎn)生一個(gè)結(jié)果列表,其中包含被調(diào)用鉤子(hook)方法的所有非None結(jié)果。

一些鉤子(hook)規(guī)范使用該firstresult=True選項(xiàng),以便鉤子(hook)調(diào)用僅執(zhí)行,直到N個(gè)注冊(cè)方法中的第一個(gè)返回非None結(jié)果,然后將其作為整個(gè)鉤子(hook)調(diào)用的結(jié)果。在這種情況下,不會(huì)調(diào)用其余的鉤子(hook)方法。

hookwrapper:在其他鉤子(hook)周圍執(zhí)行

版本2.7中的新功能。

pytest插件可以實(shí)現(xiàn)鉤子(hook)包裝器,它包裝其他鉤子(hook)實(shí)現(xiàn)的執(zhí)行。鉤子(hook)包裝器是一個(gè)生成器方法,它只產(chǎn)生一次。當(dāng)pytest調(diào)用鉤子(hook)時(shí),它首先執(zhí)行鉤子(hook)包裝器并傳遞與常規(guī)鉤子(hook)相同的參數(shù)。

在鉤子(hook)包裝器的屈服點(diǎn),pytest將執(zhí)行下一個(gè)鉤子(hook)實(shí)現(xiàn),并以Result封裝結(jié)果或異常信息的實(shí)例的形式將其結(jié)果返回到屈服點(diǎn)。因此,屈服點(diǎn)本身通常不會(huì)引發(fā)異常(除非存在錯(cuò)誤)。

以下是鉤子(hook)包裝器的示例定義:

import pytest

@pytest.hookimpl(hookwrapper=True)
def pytest_pyfunc_call(pyfuncitem):
    do_something_before_next_hook_executes()

    outcome = yield
    # outcome.excinfo may be None or a (cls, val, tb) tuple

    res = outcome.get_result()  # will raise if outcome was exception

    post_process_result(res)

    outcome.force_result(new_res)  # to override the return value to the plugin system

請(qǐng)注意,鉤子(hook)包裝器本身不返回結(jié)果,它們只是圍繞實(shí)際的鉤子(hook)實(shí)現(xiàn)執(zhí)行跟蹤或其他副作用。如果底層鉤子(hook)的結(jié)果是一個(gè)可變對(duì)象,它們可能會(huì)修改該結(jié)果,但最好避免它。

有關(guān)更多信息,請(qǐng)參閱插件文檔。

鉤子(hook)方法排序/調(diào)用示例

對(duì)于任何給定的鉤子(hook)規(guī)范,可能存在多個(gè)實(shí)現(xiàn),因此我們通常將hook執(zhí)行視為 1:N方法調(diào)用,其中N是已注冊(cè)方法的數(shù)量。有一些方法可以影響鉤子(hook)實(shí)現(xià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

這是執(zhí)行的順序:

  1. Plugin3的pytest_collection_modifyitems被調(diào)用直到屈服點(diǎn),因?yàn)樗且粋€(gè)鉤子(hook)包裝器。
  2. 調(diào)用Plugin1的pytest_collection_modifyitems是因?yàn)樗鼧?biāo)有tryfirst=True。
  3. 調(diào)用Plugin2的pytest_collection_modifyitems因?yàn)樗粯?biāo)記trylast=True(但即使沒(méi)有這個(gè)標(biāo)記,它也會(huì)在Plugin1之后出現(xiàn))。
  4. 插件3的pytest_collection_modifyitems然后在屈服點(diǎn)之后執(zhí)行代碼。yield接收一個(gè)Result實(shí)例,該實(shí)例封裝了調(diào)用非包裝器的結(jié)果。包裝不得修改結(jié)果。

這是可能的使用tryfirst,并trylast結(jié)合還 hookwrapper=True處于這種情況下,它會(huì)影響彼此之間hookwrappers的排序。

聲明新鉤子(hook)

插件和conftest.py文件可以聲明新鉤子(hook),然后可以由其他插件實(shí)現(xiàn),以便改變行為或與新插件交互:

<dt>pytest_addhooks(*pluginmanager *)[來(lái)源]

在插件注冊(cè)時(shí)調(diào)用,允許通過(guò)調(diào)用添加新的掛鉤 。pluginmanager.add_hookspecs(module_or_class, prefix)

參數(shù): | pluginmanager_pytest.config.PytestPluginManager) - pytest插件管理器

注意:
這個(gè)鉤子(hook)與之不相容hookwrapper=True。

鉤子(hook)通常被聲明為do-nothing方法,它們只包含描述何時(shí)調(diào)用鉤子(hook)以及期望返回值的文檔。

有關(guān)示例,請(qǐng)參閱xdist中newhooks.py。

可選擇使用第三方插件的鉤子(hook)

由于標(biāo)準(zhǔn)的驗(yàn)證機(jī)制,如上所述使用插件中的新鉤子(hook)可能有點(diǎn)棘手:如果你依賴未安裝的插件,驗(yàn)證將失敗并且錯(cuò)誤消息對(duì)你的用戶沒(méi)有多大意義。

一種方法是將鉤子(hook)實(shí)現(xiàn)推遲到新的插件,而不是直接在插件模塊中聲明鉤子(hook)方法,例如:

# contents of myplugin.py

class DeferPlugin(object):
    """Simple plugin to defer pytest-xdist hook functions."""

    def pytest_testnodedown(self, node, error):
        """standard xdist hook function.
 """

def pytest_configure(config):
    if config.pluginmanager.hasplugin("xdist"):
        config.pluginmanager.register(DeferPlugin())```
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容