从 pytest
源代码的角度来分析其工作原理,我们需要关注几个关键的部分,特别是 pytest
的启动过程以及测试的收集与执行。下面是基于 pytest
源代码的一个高层次的概述。
命令行解析:
pytest
的入口点是 conftest.py
文件中的 pytest.main()
函数。pytest.config.get_config()
获取配置。pytest.config.parse()
来解析命令行参数。配置加载:
pytest
会在当前目录及其父目录递归地查找配置文件,比如 pytest.ini
或 pyproject.toml
。pytest.config.Config
类来存储配置信息。插件管理:
pytest.hookspec
和 pytest.pluginmanager
来管理插件。收集器初始化:
pytest
使用 pytest.collect
模块来处理测试收集。Session.from_parent
方法创建一个新的 Session
实例。Collector.from_parent
方法用于构建收集器树。测试文件发现:
pytest
通过 Session.perform_collect
方法来遍历目录结构并发现测试模块。File.from_parent
方法用于创建 File
实例来代表测试文件。Function.from_parent
方法用于创建 Function
实例来代表测试函数。测试项构建:
collect
方法来收集文件中的测试函数。Item
实例。测试项准备:
Session.perform_setup
方法来进行一些预处理。测试项执行:
Session.runtestloop
方法控制测试项的实际执行。Item
实例,都会调用 Session.perform_test
方法来执行测试。测试结果收集:
Item
实例中。pytest_runtest_logreport
hook,该 hook 被用来处理测试报告。异常处理:
pytest
会捕获这些异常并记录下来。pytest_runtest_makereport
hook 来处理。Session
实例负责收集所有的测试结果。Session.exitstatus
属性会根据测试结果来确定程序的退出状态码。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() # 返回退出状态 return session.exitstatus # pytest/collect.py def perform_collect(session, collector): # 收集测试文件和测试函数 items = [] for item in collector.collect(): items.append(item) return items # pytest/runner.py def runtest_protocol(item, nextitem): # 执行测试项 report = item.runtest() if report is None: # 处理异常情况 report = item.makereport() # 处理测试报告 item.session._hookmanager.hook.pytest_runtest_logreport(report=report)