摘要:所有的函數(shù)都使用的命名規(guī)則,以便于查找并且同其他函數(shù)區(qū)分開來。用來每個(gè),保證被正確的定義。里還有一個(gè)選項(xiàng),用來表示這個(gè)函數(shù)是個(gè)函數(shù)。自動(dòng)注冊(cè)插件除了常規(guī)的方法注冊(cè)插件,同時(shí)提供了方法,允許通過自動(dòng)注冊(cè)插件。
前言
參考官方的這篇文章,我嘗試翻譯其中一些重點(diǎn)部分,并且拓展了相關(guān)的pluggy部分的知識(shí)。由于pytest是在pluggy基礎(chǔ)上構(gòu)建的,強(qiáng)烈建議先閱讀一下pluggy的官方文檔,這樣理解起來更加容易一點(diǎn)。
正文conftest.py可以作為最簡(jiǎn)單的本地plugin調(diào)用一些hook函數(shù),以此來做些強(qiáng)化功能。
pytest整個(gè)框架通過調(diào)用如下定義良好的hooks來實(shí)現(xiàn)配置,收集,執(zhí)行和報(bào)告這些過程:
內(nèi)置plugins:從代碼內(nèi)部的_pytest目錄加載;
外部插件(第三方插件):通過setuptools entry points機(jī)制發(fā)現(xiàn)的第三方插件模塊;
conftest.py形式的本地插件:測(cè)試目錄下的自動(dòng)模塊發(fā)現(xiàn)機(jī)制;
原則上,每個(gè)hook都是一個(gè) 1:N 的python函數(shù)調(diào)用, 這里的 N 是對(duì)一個(gè)給定hook的所有注冊(cè)調(diào)用數(shù)。所有的hook函數(shù)都使用pytest_xxx的命名規(guī)則,以便于查找并且同其他函數(shù)區(qū)分開來。
decorratorpluggy里提供了兩個(gè)decorator helper類,分別是HookspecMarker和HookimplMarker,通過使用相同的project_name參數(shù)初始化得到對(duì)應(yīng)的裝飾器,后續(xù)可以用這個(gè)裝飾器將函數(shù)標(biāo)記為hookspec和hookimpl。
hookspechook specification (hookspec)用來validate每個(gè)hookimpl,保證hookimpl被正確的定義。
hookspec 通過 add_hookspecs()方法加載,一般在注冊(cè)hookimpl之前先加載;
hookimplhook implementation (hookimpl) 是一個(gè)被恰當(dāng)標(biāo)記過的回調(diào)函數(shù)。hookimpls 通過register()方法加載。
注:為了保證hookspecs在項(xiàng)目里可以不斷演化, hookspec里的參數(shù)對(duì)于hookimpls是可選的,即可以定義少于spec里定義數(shù)量的參數(shù)。
hookwrapperhookimpl 里還有一個(gè)hookwrapper選項(xiàng),用來表示這個(gè)函數(shù)是個(gè)hookwrapper函數(shù)。hookwrapper函數(shù)可以在普通的非wrapper的hookimpls執(zhí)行的前后執(zhí)行一些其他代碼, 類似于@contextlib.contextmanager,hookwrapper必須在它的主體包含單一的yield,用來實(shí)現(xiàn)生成器函數(shù),例如:
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
生成器發(fā)送一個(gè) pluggy.callers._Result對(duì)象 , 這個(gè)對(duì)象可以在 yield表達(dá)式里指定并且通過 force_result()或者get_result() 方法重寫或者拿到最終結(jié)果。
注:hookwrapper不能返回結(jié)果 (跟所有的生成器函數(shù)一樣);
hookimpl的調(diào)用順序默認(rèn)情況下,hook的調(diào)用順序遵循注冊(cè)時(shí)的順序LIFO(后進(jìn)先出),hookimpl允許通過tryfirst, trylast*選項(xiàng)調(diào)整這一項(xiàng)順序。
舉個(gè)例子,對(duì)于如下的代碼:
# 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í)行順序如下:
Plugin3的pytest_collection_modifyitems先調(diào)用,直到y(tǒng)ield點(diǎn),因?yàn)檫@是一個(gè)hook warpper。
Plugin1的pytest_collection_modifyitems被調(diào)用,因?yàn)橛?tryfirst=True參數(shù)。
Plugin2的pytest_collection_modifyitems被調(diào)用,因?yàn)橛?trylast=True參數(shù) (不過即使沒有這個(gè)參數(shù)也會(huì)排在tryfirst標(biāo)記的plugin后面)。
Plugin3的pytest_collection_modifyitems調(diào)用yield后面的代碼. yield接收非Wrapper的result返回. Wrapper函數(shù)不應(yīng)該修改這個(gè)result。
當(dāng)然也可以同時(shí)將 tryfirst 和 trylast與 hookwrapper=True 混用,這種情況下它將影響hookwrapper之間的調(diào)用順序.
hook執(zhí)行結(jié)果處理和firstresult選項(xiàng)默認(rèn)情況下,調(diào)用一個(gè)hook會(huì)使底層的hookimpl函數(shù)在一個(gè)循環(huán)里按順序執(zhí)行,并且將其非空的執(zhí)行結(jié)果添加到一個(gè)list里面。例外的是,hookspec里有一個(gè)firstresult選項(xiàng),如果指定這個(gè)選項(xiàng)為true,那么得到第一個(gè)返回非空的結(jié)果的hookimpl執(zhí)行后就直接返回,后續(xù)的hookimpl將不在被執(zhí)行,參考后面的例子。
注: hookwrapper還是正常的執(zhí)行
hook的調(diào)用每一個(gè)pluggy.PluginManager 都有一個(gè)hook屬性, 可以通過調(diào)用這個(gè)屬性的call函數(shù)來調(diào)用hook,需要注意的是,調(diào)用時(shí)必須使用關(guān)鍵字參數(shù)語法來調(diào)用。
請(qǐng)看下面這個(gè)firstresult和hook調(diào)用例子:
from pluggy import PluginManager, HookimplMarker, HookspecMarker hookspec = HookspecMarker("myproject") hookimpl = HookimplMarker("myproject") class MySpec1(object): @hookspec def myhook(self, arg1, arg2): pass class MySpec2(object): # 這里將firstresult設(shè)置為True @hookspec(firstresult=True) def myhook(self, arg1, arg2): pass class Plugin1(object): @hookimpl def myhook(self, arg1, arg2): """Default implementation. """ return 1 class Plugin2(object): # hookimpl可以定義少于hookspec里定義數(shù)量的參數(shù),這里只定義arg1 @hookimpl def myhook(self, arg1): """Default implementation. """ return 2 class Plugin3(object): # 同上,甚至可以不定義hookspec里的參數(shù) @hookimpl def myhook(self): """Default implementation. """ return 3 pm1 = PluginManager("myproject") pm2 = PluginManager("myproject") pm1.add_hookspecs(MySpec1) pm2.add_hookspecs(MySpec2) pm1.register(Plugin1()) pm1.register(Plugin2()) pm1.register(Plugin3()) pm2.register(Plugin1()) pm2.register(Plugin2()) pm2.register(Plugin3()) # hook調(diào)用必須使用關(guān)鍵字參數(shù)的語法 print(pm1.hook.myhook(arg1=None, arg2=None)) print(pm2.hook.myhook(arg1=None, arg2=None))
得到結(jié)果如下:
[3, 2, 1] 3
可以看到,由于pm2里的hookspec里有firstresult參數(shù),在得到3這個(gè)非空結(jié)果時(shí)就直接返回了。
自動(dòng)注冊(cè)插件除了常規(guī)的register()方法注冊(cè)插件,pluggy同時(shí)提供了 load_setuptools_entrypoints()方法,允許通過 setuptools entry points 自動(dòng)注冊(cè)插件。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/43436.html
摘要:會(huì)調(diào)用向打印一些環(huán)境信息,比如插件版本,版本,操作平臺(tái)這些等。在執(zhí)行之后調(diào)用執(zhí)行的過程是否執(zhí)行取決于是否需要?jiǎng)?chuàng)建執(zhí)行的過程如果有。所有測(cè)試執(zhí)行完畢之后,返回之前的階段。結(jié)束以后,整個(gè)退出之前的階段。 pytest插件開發(fā)需要熟悉一些常用的hook函數(shù),官方對(duì)于這些hook有一份簡(jiǎn)略的文檔(目前除了小部分hook目前缺乏文檔外,見這個(gè)issue),但是各個(gè)hook的調(diào)用邏輯沒有一個(gè)直觀的...
摘要:本套代碼和邏輯是本人的勞動(dòng)成果,如果有轉(zhuǎn)載需要標(biāo)注,非常適合公司做項(xiàng)目的同學(xué)小白也可以學(xué)哦接口自動(dòng)化項(xiàng)目目錄公共方法的封裝如果不用配置文件可以使用這個(gè)方法進(jìn)行封裝但是有一定的缺陷可以不使用字典。這是在正常的命令行解析之前發(fā)生的。 ...
摘要:其中用到編程等,還需要花更多的精力去深入學(xué)習(xí),當(dāng)每項(xiàng)技能都能掌握到一定深度,才能稱為一個(gè)完整的知識(shí)體系。 都有哪些種類的配置文件 pytest.ini:pytes...
摘要:?jiǎn)栴}大部分問題是因?yàn)榘惭b了導(dǎo)致的比如此時(shí)需要先卸載然后再安裝包已經(jīng)安裝過的不用重復(fù)安裝。版本問題類似于這種一般是因?yàn)榘姹咎邔?dǎo)致建議卸載現(xiàn)有版本并安裝較低版本的。后續(xù)重裝低版本出現(xiàn)如下報(bào)錯(cuò)重裝最新版本并重裝包 ...
摘要:在測(cè)試行業(yè),如果利用作為腳本語言開發(fā)自動(dòng)化測(cè)試用例,可用的框架有等主流可供選擇,個(gè)人感覺較之和應(yīng)該算是現(xiàn)階段最靈活,功能最全面,擴(kuò)展最豐富的框架了。不知道各位在做自動(dòng)化的時(shí)候有沒有遇到過用例數(shù)過多,單機(jī)執(zhí)行效率不高的困擾。 在測(cè)試行業(yè),如果利用python作為腳本語言開發(fā)自動(dòng)化測(cè)試用例,可用...
閱讀 1586·2021-11-24 09:39
閱讀 1090·2021-11-22 15:11
閱讀 2243·2021-11-19 11:35
閱讀 1657·2021-09-13 10:37
閱讀 2516·2021-09-03 10:47
閱讀 2190·2021-08-30 09:47
閱讀 1662·2021-08-20 09:39
閱讀 2942·2019-08-30 14:13