首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

pytest的内置插件盘点4:runner

4. 内置插件 runner

插件路径:_pytest.runner

实现的 hook

调用的 hook

pytest_runtest_logfinish

pytest_runtest_makereport

pytest_exception_interact

pytest_collectstart

pytest_runtest_logreport

pytest_runtest_logstart

pytest_make_collect_report

插件功能

创建参数--durations,显示 N 个最慢用例的耗时情况

创建参数--durations-min,显示超过 M 秒的用例的耗时情况

把用例分为setp、call、teardown3 个阶段执行,并生成各阶段的报告

支持多级夹具:session -> package-> module -> class -> function

执行用例时判断参数:

如果收到参数--setupshow,显示夹具信息

如果收到参数--setuponly, 仅显示夹具信息,不执行用例

代码片段

def runtestprotocol( item: Item, log: bool = True, nextitem: Optional[Item] = None) -> List[TestReport]: hasrequest = hasattr(item, "_request") if hasrequest and not item._request: # type: ignore[attr-defined] # This only happens if the item is re-run, as is done by # pytest-rerunfailures. item._initrequest() # type: ignore[attr-defined] rep = call_and_report(item, "setup", log) reports = [rep] if rep.passed: if item.config.getoption("setupshow", False): show_test_item(item) if not item.config.getoption("setuponly", False): reports.append(call_and_report(item, "call", log)) reports.append(call_and_report(item, "teardown", log, nextitem=nextitem)) # After all teardown hooks have been called # want funcargs and request info to go away. if hasrequest: item._request = False # type: ignore[attr-defined] item.funcargs = None # type: ignore[attr-defined] return reports

class CallInfo(Generic[TResult]): @classmethod def from_call( cls, func: "Callable[[], TResult]", when: "Literal['collect', 'setup', 'call', 'teardown']", reraise: Optional[ Union[Type[BaseException], Tuple[Type[BaseException], ...]] ] = None, ) -> "CallInfo[TResult]": """Call func, wrapping the result in a CallInfo.

:param func: The function to call. Called without arguments. :param when: The phase in which the function is called. :param reraise: Exception or exceptions that shall propagate if raised by the function, instead of being wrapped in the CallInfo. """ excinfo = None start = timing.time() precise_start = timing.perf_counter() try: result: Optional[TResult] = func() except BaseException: excinfo = ExceptionInfo.from_current() if reraise is not None and isinstance(excinfo.value, reraise): raise result = None # use the perf counter precise_stop = timing.perf_counter() duration = precise_stop - precise_start stop = timing.time() return cls( start=start, stop=stop, duration=duration, when=when, result=result, excinfo=excinfo, _ispytest=True, )

用例的报告,在执行是同步进行:call_and_report

每个用例执行分为 3 个阶段,并生成 3 份报告 :setp、call、teardown

用例执行过程非常精彩:

根据执行阶段,选择 hook:pytest_runtest_xxx

把用例丢进 hook 中,调用 hook

得到调用结果:阶段、开始时间、结束时间、耗时、返回值、异常信息

将调用结果丢进 hookpytest_runtest_makereport中,生成报告

继续执行下一个阶段

所有阶段执行完毕后,执行下一个用例

简评

在介绍 main 插件的时候给你们说过,他把【用例收集】和【用例执行】的工作委托给了 session 插件。

其实 session 自己只干了用例收集的活儿,用例执行又被转包给了 runner 了。

当然这么做也有合理性,一方面 session 插件现在只干各用例收集的事就已经 400 + 行代码了,如果再包揽用例执行的活,代码量奔 1k 去了,着实不利于维护。

还有一点,session 插件本身是在 main 插件内创建的,加上 main 插件的内容,一个文件内会挤进去 1400 多行,写代码的人和看代码的人,都会吐。。。

不过下一个插件 fixture,义无反顾的在一个文件里写了 1600 多行代码。。。敬请期待

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OmE38UixRl6um--LDKEv0qvg0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券