从源码的角度重新认识pytest(下)

4.pytest 启动入口

pytest 的启动方式有三种:

  1. 命令行
pytest

2. 命令行

python -m  pytest

3. python 代码

import pytest
pytest.main()

这三种方式都将执行_pytest.config.main 函数, 其源码如下

def main(
    args: Optional[Union[List[str], "os.PathLike[str]"]] = None,
    plugins: Optional[Sequence[Union[str, _PluggyPlugin]]] = None,
) -> Union[int, ExitCode]:
    """Perform an in-process test run.

    :param args: List of command line arguments.
    :param plugins: List of plugin objects to be auto-registered during initialization.

    :returns: An exit code.
    """
    try:
        try:
            config = _prepareconfig(args, plugins)
        except ConftestImportFailure as e:
            exc_info = ExceptionInfo.from_exc_info(e.excinfo)
            tw = TerminalWriter(sys.stderr)
            tw.line(f"ImportError while loading conftest '{e.path}'.", red=True)
            exc_info.traceback = exc_info.traceback.filter(
                filter_traceback_for_conftest_import_failure
            )
            exc_repr = (
                exc_info.getrepr(style="short", chain=False)
                if exc_info.traceback
                else exc_info.exconly()
            )
            formatted_tb = str(exc_repr)
            for line in formatted_tb.splitlines():
                tw.line(line.rstrip(), red=True)
            return ExitCode.USAGE_ERROR
        else:
            try:
                ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main(
                    config=config
                )
                try:
                    return ExitCode(ret)
                except ValueError:
                    return ret
            finally:
                config._ensure_unconfigure()
    except UsageError as e:
        tw = TerminalWriter(sys.stderr)
        for msg in e.args:
            tw.line(f"ERROR: {msg}\n", red=True)
        return ExitCode.USAGE_ERROR

从源码可以了解到,main 函数主要做了这么几件事情:

  1. 加载配置(15 行)
  2. 调用插件 hook(34 行)
  3. 返回结束代码(31、38、47 行)

由此可知,pytest 启动后,便是通过调用插件的方式完成各项作业。

5. 小结

通过对 pytest 源码的初步分析,现在我对pytest有了全新的认识:

pytest 内部使用了大量插件,

甚至可以说 :pytest 本身就是由 N 个插件的组合而来!

这么多内部插件,还有更多的第三方开发插件,都是通过 pluggy 相互交织在一起,实现出各种各样的功能,使pytest生态庞大起来

我现在也有了对pytest 的剖析基本思路:

  1. 掌握插件系统 pluggy 的运行机制
  2. 掌握 pytest 内容定义 hook 及触发时机
  3. 掌握 pytest 内置插件功能及具体实现方式
  4. 掌握pytest常见功能的运行流程和细节,比如配置文件、conftest、收集用例、捕获输入等

下节预告:拿下 pluggy!

本文系《pytest源码剖析》系列内容,首发于公众号

正在连载,欢迎关注

你可能感兴趣的:(pytest源码剖析,pytest,java,前端,软件测试,python)