从pytest源码的角度分析pytest工作原理


pytest
源代码的角度来分析其工作原理,我们需要关注几个关键的部分,特别是
pytest
的启动过程以及测试的收集与执行。下面是基于
pytest
源代码的一个高层次的概述。

pytest 的启动过程

  1. 命令行解析:


    • pytest
      的入口点是
      conftest.py
      文件中的
      pytest.main()
      函数。
    • 在这个函数中,首先通过
      pytest.config.get_config()
      获取配置。
    • 接着使用
      pytest.config.parse()
      来解析命令行参数。
  2. 配置加载:


    • pytest
      会在当前目录及其父目录递归地查找配置文件,比如
      pytest.ini

      pyproject.toml
    • 使用
      pytest.config.Config
      类来存储配置信息。
  3. 插件管理:


    • 通过
      pytest.hookspec

      pytest.pluginmanager
      来管理插件。
    • 插件可以在各个阶段被注册并调用。

测试收集过程

  1. 收集器初始化:


    • pytest
      使用
      pytest.collect
      模块来处理测试收集。
    • Session.from_parent
      方法创建一个新的
      Session
      实例。
    • Collector.from_parent
      方法用于构建收集器树。
  2. 测试文件发现:


    • pytest
      通过
      Session.perform_collect
      方法来遍历目录结构并发现测试模块。
    • File.from_parent
      方法用于创建
      File
      实例来代表测试文件。
    • Function.from_parent
      方法用于创建
      Function
      实例来代表测试函数。
  3. 测试项构建:


    • 一旦发现了测试文件,就会通过
      collect
      方法来收集文件中的测试函数。
    • 测试函数会被转换成
      Item
      实例。

测试执行过程

  1. 测试项准备:


    • 在测试开始之前,会调用
      Session.perform_setup
      方法来进行一些预处理。
    • 这个阶段可能包括设置环境变量、初始化数据库连接等。
  2. 测试项执行:


    • Session.runtestloop
      方法控制测试项的实际执行。
    • 对于每一个
      Item
      实例,都会调用
      Session.perform_test
      方法来执行测试。
  3. 测试结果收集:


    • 测试执行的结果会被收集并存储在
      Item
      实例中。
    • 可能会触发
      pytest_runtest_logreport
      hook,该 hook 被用来处理测试报告。
  4. 异常处理:


    • 如果测试过程中发生异常,
      pytest
      会捕获这些异常并记录下来。
    • 异常可以通过
      pytest_runtest_makereport
      hook 来处理。

测试报告生成

  1. Session
    实例负责收集所有的测试结果。
  2. Session.exitstatus
    属性会根据测试结果来确定程序的退出状态码。
  3. pytest
    可以生成多种格式的报告,这取决于安装的插件。

示例代码片段

下面是一些示例代码片段,展示了
pytest
源代码中的关键部分:

#pytest/conftest.py
def main(args=None):#解析命令行参数
    config =get_config(args)#加载插件
    pm =PluginManager()
pm.load_setuptools_entrypoints(
'pytest11')#创建 Session 实例 session = Session.from_parent(config, plugins=pm)#执行测试 session.runtestloop()#返回退出状态 returnsession.exitstatus#pytest/collect.py defperform_collect(session, collector):#收集测试文件和测试函数 items =[]for item incollector.collect():
items.append(item)
returnitems#pytest/runner.py defruntest_protocol(item, nextitem):#执行测试项 report =item.runtest()if report isNone:#处理异常情况 report =item.makereport()#处理测试报告 item.session._hookmanager.hook.pytest_runtest_logreport(report=report)

标签: none

添加新评论