昨天跟大家聊了 pytest 自动化框架的基础用法用例发现、fixture、参数化、简单插件不少同学私信说面试总被问 “pytest 底层原理”“插件怎么写”“hook 是什么”**只会用不够得懂点内核与扩展。今天就把pytest 底层执行流程 钩子机制 自定义插件开发 fixture 底层原理一次性讲透面试 / 实际造轮子都能用得上。一、先看全貌pytest 底层架构pytest 核心是轻量内核 插件化Hook 驱动 节点树用例管理 Fixture 依赖注入。内核只负责生命周期调度启动 → 收集 → 执行 → 报告 → 结束所有 “功能” 都是插件内置插件 第三方插件 你写的 conftest / 自定义插件用例被组织成Node 树Session → Package → Module → Class → FunctionFixture 本质是带作用域的依赖注入 资源生命周期管理二、pytest 完整生命周期面试必背敲下 pytest底层跑的是这一条链1.入口pytest.main() → 创建 Config PluginManager2.初始化_prepareconfig → 加载插件、解析配置 / 命令行3.收集用例pytest_collection → 遍历目录识别 test_.py / Test类 / test_* 函数4.执行循环pytest_runtestloop → 逐个执行用例每个用例三步Setupfixture 执行Call跑 test 函数Teardownfixture 清理5.报告pytest_runtest_makereport → 生成结果6.结束pytest_sessionfinish → 汇总、退出码一句话总结pytest 就是靠一堆 Hook 串起来的生命周期。三、核心扩展Hook钩子是什么1. 通俗理解Hook 框架留好的 “回调口子”你在这些口子上挂自己函数框架跑到对应阶段就自动调用你的代码。比如收集用例前你可以动态加用例 / 过滤用例每个用例执行前你可以打日志 / 初始化环境执行后你可以自定义报告 / 发通知2. 常用内置 Hook高频# conftest.py 里直接写不需要装饰器defpytest_addoption(parser):加自定义命令行参数parser.addoption(--env,defaulttest,help指定环境)defpytest_collection_modifyitems(config,items):收集完用例后过滤/排序/打标记foriteminitems:ifslowinitem.name:item.add_marker(pytest.mark.slow)defpytest_runtest_setup(item):每个用例执行前print(f 准备执行{item.nodeid})defpytest_runtest_teardown(item):每个用例执行后print(f 执行完成{item.nodeid})defpytest_sessionfinish(session,exitstatus):整个测试结束后汇总报告、发钉钉/邮件print(f 用例总数{session.testscollected})3. Hook 底层原理pytest 基于 pluggy 库做插件管理所有 hook 按 pytest_* 命名插件启动时注册 hook 实现框架通过 config.hook.xxx() 触发所有注册函数1:N 调用四、Fixture 底层原理面试常问为什么比 setup/teardown 强1. Fixture 本质不是 “函数”是带作用域的资源工厂 依赖注入容器yield 前 setup后 teardown作用域控制生命周期function(默认)/class/module/session底层执行流程很关键1.收集用例时分析用例依赖的 fixture递归解析2.按依赖顺序 作用域实例化 fixture3.注入到 test 函数4.用例结束反向销毁作用域长的最后销毁为什么比 unittest 灵活✅ 依赖注入用例只管声明要什么不管怎么创建✅ 作用域精细数据库连接用 session临时文件用 function✅ 可叠加 / 可覆盖局部 conftest 覆盖全局就近原则五、实战写一个自定义 pytest 插件可直接用场景想实现命令行加 --env所有用例自动带环境标记执行前后打日志1. 目录结构tests/├── conftest.py# 本地插件/hook└── test_demo.py2.conftest.py完整代码importpytest# 1. 加命令行参数defpytest_addoption(parser):parser.addoption(--env,defaulttest,choices[dev,test,prod],help运行环境)# 2. 全局 fixture获取环境pytest.fixture(scopesession)defenv(request):returnrequest.config.getoption(--env)# 3. 收集用例后自动加标记defpytest_collection_modifyitems(config,items):envconfig.getoption(--env)foriteminitems:item.add_marker(getattr(pytest.mark,env))# 4. 每个用例前后日志defpytest_runtest_setup(item):print(f\n[SETUP] 开始{item.nodeid})defpytest_runtest_teardown(item):print(f[TEARDOWN] 结束{item.nodeid})3. 测试用例 test_demo.pydeftest_sample(env):print(f当前环境{env})assert114. 运行pytest tests/-v--envdev效果自动带环境标记、前后日志、全局环境 fixture。六、面试高频问题直接背pytest 底层架构是什么插件化 Hook 驱动 节点树 Fixture 依赖注入内核轻量功能靠插件。fixture 作用域有哪些执行顺序function/class/module/session按依赖顺序创建反向销毁。hook 和 fixture 区别hook 改框架流程收集 / 执行 / 报告fixture 管测试资源前置 / 后置 / 数据。如何写一个 pytest 插件实现 hook 函数 → 注册 → 打包或直接放 conftest七、总结pytest 强大不是因为语法多复杂而是内核极简只做调度扩展极强Hook 插件体系资源管理优雅Fixture 依赖注入 作用域会用只是入门懂底层、会写插件、能定制流程才是测开 / 高级测试的核心竞争力。