ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PyCharm中pytest+selenium空套件与测试报告异常的完整解决方案

PyCharm中pytest+selenium空套件与测试报告异常的完整解决方案 先说实话这种报错我前前后后不知道见过多少次了。pytestselenium在PyCharm里一运行就提示空套件然后每次实例化的时候又弹无法附加测试报告到测试框架或者测试框架意外退出这基本上是每个刚开始在PyCharm里折腾pytestselenium的人都会撞上的墙。别看报错挂着两三个不同的现象其实很多时候它们是一根藤上的瓜pytest 没收集到用例PyCharm 的测试运行器又没把结果接住于是IDE就给你甩了一堆看起来毫无关联的英文提示。这篇文章我把整套排查思路和最终能跑的配置方案完整写下来前半部分是为什么后半部分是怎么解决最后还有一个速查表和几个值得收藏的排错技巧。无论你是刚接触自动化测试还是已经写了一阵子脚本遇到类似问题都可以直接照搬。1. 先弄清楚这串报错到底在说什么1.1 空套件和无法附加测试报告是两个环节的故障很多人被这个组合报错搞懵是因为没分清这两句话分别来自哪里。先说 Empty suite空套件。这是 pytest 自身在收集测试用例阶段给出的结论。pytest 会扫描你指定的目录、文件然后根据一套默认规则把符合条件的内容识别为测试用例。如果一圈扫下来一个用例都没找到它就会在终端里输出类似 no tests ran 的提示在 PyCharm 的测试树面板里则直接显示 Empty suite。再说 Error attaching test report to test framework 或 Test framework quit unexpectedly无法附加测试报告到测试框架/测试框架意外退出。这句话是 PyCharm 的测试运行器runner输出。PyCharm 不是直接在终端里执行 pytest 看输出它会让内置的 pytest 插件跑完测试后把结果转成 IDE 能识别的测试树结构。如果这个转换、附加的过程出了问题IDE 就会提示无法附加测试报告严重时整个测试进程崩溃表现为测试框架意外退出。1.2 为什么这两件看起来不相关的事总是一起出现这是因为 PyCharm 运行 pytest 时其实是收集用例 运行用例 上传报告一串流程。一旦第一步收集到的用例数就是 0PyCharm 在第二步、第三步处理空结果时配合版本兼容性问题就很容易触发无法附加测试报告这类 runner 层面的报错。换句话说如果你只盯着后半句去搜可能会误入排除 PyCharm 缓存、重装插件的深坑但真正根子往往在前半句——pytest 压根没找到你的测试用例。所以这篇文章的重心我会放在如何让 pytest 正确收集到用例以及如何让 PyCharm 的 runner 稳定接住结果这两个层面。2. 空套件的常见原因与逐个排查2.1 默认命名规则是第一个坎pytest 不需要额外配置就能识别三类命名文件名必须是test_*.py或者*_test.py类名必须是Test开头比如TestLogin函数名或方法名必须以test_开头比如test_login_success很多人在这个坎上摔跟头我举几个真实见到的写法# 文件名叫 login_test.py函数叫 login_check() def login_check(): ...这个例子里面文件名login_test.py是符合规则的但函数名login_check()不是以test_开头pytest 不会收集它。# 文件名 test_login.py类名 LoginTest注意少了 Test 前缀 class LoginTest: def test_login(self): ...类名LoginTest其实是以Test结尾但 pytest 的默认规则要求的是Test开头所以这个类里面即使有test_login方法pytest 默认也不会收集。还有一个非常隐蔽的坑如果你把测试方法定义在普通类里而且类名完全没有Test即使方法叫test_loginpytest 默认规则下也不会收集。因为 pytest 的默认收集规则对类是类名以 Test 开头才扫描内部方法。排查建议不要把玩花活按最朴素的规则来。文件名test_*.py函数名test_*类名实属必要再用用了就规规矩矩写Test*。2.2 PyCharm 运行配置里的 target 选错了如果你确认文件命名和函数命名都符合规则但 PyCharm 里依然显示空套件那问题很可能出在运行配置Run Configuration上。PyCharm 里运行 pytest 时需要指定 target目标。在 Run/Debug Configurations 窗口Python tests - pytest 这个类型的配置里target 可以选择模块、文件、目录等。最常见的问题是target 指向了一个不存在的文件路径或者指向一个具体文件但文件里没有符合规则的用例。我建议在项目初期尽量把 target 设为整个目录比如你的测试用例都放在tests目录下就选择tests目录。这样 pytest 会递归扫描目录下所有符合条件的文件避免因 target 指向太细而漏掉用例。尤其是多人协作项目target 指向目录比指向某个文件稳定得多。2.3 自定义命名规则搞出来的反效果为了迎合某些团队代码风格很多人会在pytest.ini或pyproject.toml里写自定义收集规则[pytest] python_files test_*.py *_test.py check_*.py python_functions test_* check_*逻辑上没问题但我不止一次看到配置文件里有类似这样的写法[pytest] python_functions test_*乍一看没毛病。但假如你的测试文件里函数叫verify_login()不在test_*范围内那 pytest 依然不会收集。注意覆盖式配置不像增量式配置它写的规则就是全部规则不是除此之外再加内置规则。还有更隐蔽的比如python_classes *Test原本只是想兼容LoginTest这种写法结果加上之后某些类的继承关系异常导致收集阶段直接报错连带出现测试框架意外退出。这种叠加问题会让空套件和 runner 崩溃同时出现。我的建议是项目初期不要配置 python_functions / python_classes完全用默认规则。等整个流程跑通再按需调整。2.4 路径和 conftest 导致的收集失败pytest 在收集测试模块时会执行导入操作。如果你在conftest.py里写了 fixture但这个 fixture 在导入阶段就会报错比如调用了一个不存在的 webdriver 方法那整个模块的收集结果会被标记为 error而不是作为一个正常用例被加入测试套件。这也会引发空套件。因为 pytest 收集不到可运行的用例只收集到 error 事件IDE 端点可能不会把 error 当作用例渲染出来你就只看到 Empty suite。另一个相关问题是项目根目录没有加入到 Python 路径中。如果你的测试文件里写了from pages.login_page import LoginPage而 PyCharm 没有把项目根目录标记为 Sources Root或者 pytest 的 rootdir 配置有误导入阶段就会 ModuleNotFoundError当前文件收集失败测试树为空。排查方法在 PyCharm 终端里直接执行pytest --collect-only -v如果输出里能看到你的测试文件、测试用例甚至能看到明显的 ImportError 或 fixture 报错那说明问题在收集阶段如果输出也显示 no tests collected那就回到命名规则和 target 两个思路继续查。3. 无法附加测试报告或者测试框架意外退出怎么治3.1 它和 PyCharm 运行器的关系展开讲一下 PyCharm 收集测试结果的机制。PyCharm 执行 pytest 时会在底层命令里附加一些参数让 pytest 输出一种 IDE 能解析的报告格式。接着 PyCharm 会读取这份临时报告文件把它解析成测试树显示在运行窗口的左侧。无法附加测试报告到测试框架这句话可以理解为pytest 跑完了甚至用例可能也收集到了但 PyCharm 没拿到它预期的报告文件或者在读取时报错于是它认为测试框架意外退出。所以排查重点不是pytest 能不能跑而是PyCharm 能不能拿到那份中间报告。以下几点是反复踩坑后总结出来的高发原因。3.2 pytest-html 这类报告插件容易和 IDE runner 打架如果你装了pytest-html或者allure-pytest并且在pytest.ini或者启动参数里带了--htmlreport.html、--alluredirallure-results这类参数那么在你点击 PyCharm 的 Run 按钮时pytest 会产生两层报告一层给你指定的 html 文件另一层给 PyCharm 解析。某些插件版本会改变 pytest 的执行流程导致 PyCharm 读取它那份报告时拿到空文件于是报无法附加测试报告。我见过最典型的情况pytest.ini里写死了[pytest] addopts --htmlreport.html --self-contained-html这样每次运行都会先尝试生成 html 报告再进入 IDE 解析阶段。只要 html 生成过程稍微有点异常整个 runner 就崩。解决方式把报告生成参数从pytest.ini里移走只在需要生成报告时在终端手敲参数。如果一定想保留可以临时把 addopts 注释掉跑一次 PyCharm 看问题是不是立刻消失。如果消失就是报告插件冲突没跑。3.3 pytest 版本和 PyCharm 版本的兼容性这个问题在 PyCharm 2022、2023 这几个版本尤其明显。我用过的组合里pytest 7.x 配合旧版 PyCharm在特定情况下会出现 junit 报告解析异常表现就是无法附加测试报告。换成 pytest 8.x 之后又因为 PyCharm 自身的 pytest 插件版本过老产生新的问题。这类版本冲突没有一劳永逸的答案我推荐的思路是先锁定一个稳定组合。如果你用的是 PyCharm 2023 或更新版本优先用 pytest 7.4 或 8.x 中比较新的稳定版如果你被困在旧版本 IDE可以考虑降级 pytest 到 6.x 试试。重点是项目里务必用虚拟环境不要用全局 Python否则升级/降级很容易污染环境导致问题更难查。3.4 Python 解释器对不上是最容易忽视的隐形炸弹有一种非常气人的情况在 PyCharm 终端里执行pytest -v一切正常能收集、能运行、能出结果但点击 Run 按钮就是空套件或者无法附加测试报告。这时候大概率是 PyCharm 当前项目选择的解释器和你终端里用的解释器不是同一个。你可能在终端里激活了.venv虚拟环境但 PyCharm 的项目解释器还指向系统 Python或者指向另一个环境的 Python。PyCharm 用它的解释器去执行 pytest而那个环境里压根没装 pytest或者装的 pytest 版本不一样自然就崩了。检查路径File - Settings - Project - Python Interpreter确认解释器路径是虚拟环境下的 python。再看终端里执行which pytestWindows 上是where pytest得到的 pytest 路径两个应该对应同一个环境的 Scripts 目录。3.5 路径里的中文、空格以及杀毒软件的干扰PyCharm 在运行 pytest 时会在临时目录生成报告文件如果项目路径或者系统临时目录路径里包含中文、空格、特殊符号某些 IDE 版本的 runner 在解析路径时会出错表现为测试框架意外退出。另外Windows 上杀毒软件实时监控临时目录也可能把 PyCharm 刚生成的临时报告文件当风险文件拦截。这样 IDE 读取时文件已经不存在报错自然出现。之前我帮人远程排查过一个问题命令行跑测试啥事没有IDE 里死活报无法附加测试报告最后发现是杀毒软件把临时目录下的 xml 文件隔离了。把 PyCharm 的临时目录加白名单或者把项目整个放到纯英文路径下问题立刻消失。3.6 特定 fixture 写法导致 runner 崩溃还有一种框架意外退出和 fixture 的 scope 有关。比如你在conftest.py里有pytest.fixture(scopesession) def driver(): ...如果 driver 初始化过程中请求了远程地址或者创建了多个浏览器实例在 session 结束时清理动作抛了异常PyCharm 的 runner 读取结果时可能崩溃。这个不如前面几个那么常见但一旦碰上就非常隐蔽。我的做法是排查阶段把所有自定义 fixture 先简化成 yield 形式保证 finalizer 不抛异常。比如pytest.fixture def driver(): options webdriver.ChromeOptions() options.add_argument(--headlessnew) driver webdriver.Chrome(optionsoptions) yield driver driver.quit()先用最简单的结构跑通再逐步加复杂的 teardown 逻辑。4. 从零跑通一个 pytestselenium 项目的完整实操这一节我们直接跳过理论我把一套验证过的配置过程写出来你按顺序执行大概率能把问题一次解决。我假设你用的是 PyCharm 2023 以后的版本Python 3.10 以上selenium 4.x。4.1 创建项目结构先建一个干净目录比如demo_project注意整个路径不要有中文和空格。目录结构如下demo_project/ ├── pytest.ini ├── conftest.py └── tests/ └── test_login.py这里我把conftest.py放在项目根目录这样它能作用于所有子目录的测试。tests目录放测试文件。4.2 创建虚拟环境并安装依赖打开 PyCharm 自带的 Terminal先创建虚拟环境python -m venv .venv激活虚拟环境Windows:.venv\Scripts\activatemacOS / Linux:source .venv/bin/activate然后安装依赖pip install pytest selenium webdriver-manager这里我特意加上了webdriver-manager它可以自动帮你下载对应版本的 chromedriver省去手动配置浏览器驱动的痛苦。另外为了让 PyCharm 运行时也能识别虚拟环境安装完成后去 File - Settings - Project - Python Interpreter选择Existing再指向.venv\Scripts\python.exeWindows或者.venv/bin/pythonmac/linux。4.3 编写最小可运行的配置和代码在pytest.ini里写[pytest] addopts -v先不要加任何--html、--alluredir之类的参数。这是为了避免插件冲突干扰排查。在conftest.py里写一个最简单的 fixtureimport pytest from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager pytest.fixture def driver(): service Service(ChromeDriverManager().install()) options webdriver.ChromeOptions() options.add_argument(--start-maximized) web_driver webdriver.Chrome(serviceservice, optionsoptions) yield web_driver web_driver.quit()在tests/test_login.py里写一个最简单不过的用例目的只是验证收集和运行from selenium.webdriver.common.by import By def test_open_baidu(driver): driver.get(https://www.baidu.com) assert driver.title is not None注意这里我用了一个公开的正常网址只是为了验证流程不是为了教大家抓取数据。测试目标可以是任意你能正常访问的站点换成公司内网测试环境地址也完全没问题。4.4 PyCharm 配置 pytest 默认运行器设置入口File - Settings - Tools - Python Integrated Tools - Testing。在 Default test runner 下拉框里选择pytest。这里必须设置否则 PyCharm 默认可能用 unittest 运行器去跑 pytest 的用例收集逻辑完全不同很容易出现空套件。设置完成后右键tests/test_login.py选择 Run pytest in test_login。PyCharm 会自动创建一个 pytest 类型的运行配置target 默认指向这个文件。4.5 先用命令行验证再用 PyCharm 验证在终端里激活虚拟环境后执行pytest --collect-only -v如果终端输出里有类似tests/test_login.py::test_open_baidu说明收集成功。接着执行pytest -v正常运行且有一个用例通过。这一步的目的是把代码问题和PyCharm 集成问题分开如果命令行正常那后面只剩 PyCharm 运行器的问题如果命令行也是空套件说明问题还是出在 pytest 收集阶段回到第 2 节排查。最后再回到 PyCharm 里点击 Run正常情况下左侧测试树会出现一个test_open_baidu用例运行后显示通过。到这一步pytestselenium 在 PyCharm 里的基础链路就算真正跑通了。5. 常见问题速查表与独家排查技巧5.1 速查表现象、优先排查点、快速验证方法现象优先排查项快速验证方法Empty suite文件/函数命名是否符合默认规则pytest --collect-only -vEmpty suitePyCharm 运行配置 target 是否指向正确目录把 target 改为 tests 目录Empty suitepytest.ini 中 python_files 是否写错注释掉自定义规则后再试无法附加测试报告pytest-html / allure 插件冲突去掉 addopts 中的 --html 参数测试框架意外退出pytest 版本与 PyCharm 版本不兼容调整 pytest 版本后重试收集时报导入错误conftest.py 里的 fixture 报错临时注释 fixture先跑一个不含 fixture 的用例命令行能跑、PyCharm 不能跑解释器没选对确认项目解释器和终端解释器一致--collect-only正常但 IDE 崩溃临时目录被拦截/路径含中文项目移到纯英文路径关杀毒软件测试5.2 技巧一别在 IDE 里反复点 Run先回终端看完整日志PyCharm 的测试运行器会对 pytest 的输出做二次加工很多底层报错会被它吞掉只给你留下一句笼统的框架意外退出。这就像在看一部被打了马赛克的监控视频怎么猜都猜不全。正确做法是先在终端里直接执行 pytest。终端的输出才是 pytest 的完整原始日志包含错误堆栈、收集信息、插件加载顺序等。等终端里跑通了再回 PyCharm 点 Run。如果终端能跑通但 IDE 报错那九成是 IDE runner 本身的问题排查范围就小很多。5.3 技巧二改完配置如果还是莫名报错试试 Invalidate CachesPyCharm 的测试运行器有时会缓存一些异常状态导致某些配置改了也不生效。这时候 File - Invalidate Caches / Restart选择 Invalidate and Restart清掉缓存后重启。这个操作不会删你的代码只是清 IDE 的内部缓存。不少怎么改都没用的诡异问题就这样直接消失了。5.4 技巧三把 pytest.ini 里所有 addopts 先清空再逐项加回很多人习惯在pytest.ini里写[pytest] addopts --htmlreport.html --self-contained-html --alluredirallure-results这不是不行但在 PyCharm 集成阶段这些参数会让 IDE 重复生成多份报告。我排查时第一步永远是清空addopts让 PyCharm 用最干净的参数执行 pytest。等确认 PyCharm 能正常跑了再逐项加回这些参数每加一个跑一次。用二分法定位到底是谁在捣乱。5.5 技巧四禁用 cacheprovider 排除缓存干扰pytest 的.pytest_cache目录偶尔也会干扰收集尤其是你从旧项目复制过来的配置缓存里残留了旧路径。可以用这个命令做一次验证pytest -p no:cacheprovider -v如果这样收集正常说明缓存有干扰删除项目根目录下的.pytest_cache目录再正常执行 pytest 即可。6. 我个人在实际操作中的体会这几类问题排查得多了最大的感受就是不要被报错文案牵着走。PyCharm 那些英文提示只能告诉你最后一步出了问题不代表第一步就出了问题。你真正要做的是把链路拆开先用命令行确认 pytest 收集到用例没有再确认运行本身有没有错误最后才轮到 PyCharm 的 runner 环节。这三层一层一层剥基本没有查不出来的。另外如果你现在还在用全局 Python 环境做这些事我真的建议尽早切到虚拟环境。很多 pytest 插件、selenium 版本的问题本质上都是多个项目共用一套环境导致的互相污染。每一样都只有一条路走到黑的人不如花五分钟建一个干净的 venv后面能少踩无数坑。最后再分享一个小技巧如果你在 PyCharm 里已经确定了项目解释器是虚拟环境但点击 Run 依然空套件可以检查一下项目解释器下拉框下面那个 Package 列表里有没有 pytest。如果在列表里看不到 pytest说明 PyCharm 对解释器包的索引还没刷新。设置里点一下 Reload the list of available packages 按钮刷新或者直接把解释器重新选一遍问题经常就这样迎刃而解。
返回列表