pytest的内置插件盘点4:runner

本文详细解析了pytestrunner插件的功能,包括内置插件、执行阶段划分(setup,call,teardown)、参数控制(如--durations和--setupshow)以及其在用例收集和执行中的作用。文章还提到代码结构优化的原因,强调了模块化和维护性的重要性。
摘要由CSDN通过智能技术生成

本文系《pytest源码剖析》系列内容

正在连载,欢迎关注

图片

4. 内置插件 runner

插件路径:_pytest.runner

实现的 hook

hooktryfirsttrylastoptionalhookhookwrapperwrapper
pytest_addoptionFalseFalseFalseFalseFalse
pytest_make_collect_reportFalseFalseFalseFalseFalse
pytest_report_teststatusFalseFalseFalseFalseFalse
pytest_runtest_callFalseFalseFalseFalseFalse
pytest_runtest_makereportFalseFalseFalseFalseFalse
pytest_runtest_protocolFalseFalseFalseFalseFalse
pytest_runtest_setupFalseFalseFalseFalseFalse
pytest_runtest_teardownFalseFalseFalseFalseFalse
pytest_sessionfinishFalseFalseFalseFalseFalse
pytest_sessionstartFalseFalseFalseFalseFalse
pytest_terminal_summaryFalseFalseFalseFalseFalse

调用的 hook

  • pytest_runtest_logfinish

  • pytest_runtest_makereport

  • pytest_exception_interact

  • pytest_collectstart

  • pytest_runtest_logreport

  • pytest_runtest_logstart

  • pytest_make_collect_report

插件功能

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

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

  3. 把用例分为 setpcallteardown3 个阶段执行,并生成各阶段的报告

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

  5. 执行用例时判断参数:

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

    2. 如果收到参数 --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,        )
  1. 用例的报告,在执行是同步进行: call_and_report

  2. 每个用例执行分为 3 个阶段,并生成 3 份报告 : setpcallteardown

  3. 用例执行过程非常精彩:

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

    2. 把用例丢进 hook 中,调用 hook

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

    4. 将调用结果丢进 hook pytest_runtest_makereport 中,生成报告

    5. 继续执行下一个阶段

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

简评

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

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

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

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

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

首发于公众号:测试开发研习社

原创不易,喜欢请星标+点赞+在看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值