Ubuntu22.04下使用pytest-qt的qtbot fixture出现Segmentation Fault问题
在Ubuntu 22.04使用pytest-qt的qtbot fixture时触发段错误
环境
- Ubuntu 22.04
- Python 3.10.4
- Poetry 项目管理工具
- PyQt6 6.5.1
- pytest 7.4.0
- pytest-qt 4.2.0
问题
测试用例中引入qtbot fixture后,运行pytest会出现Segmentation Fault;移除qtbot后测试可正常执行。以下是最小复现流程:
复现步骤
$ poetry new --src myproject $ cd myproject $ poetry add pyqt6 $ poetry add --group=dev pytest $ poetry add --group=dev pytest-qt $ cat <<'END' > pytest.ini [pytest] qt_api=pyqt6 END $ cat <<'END' > src/myproject/main.py from PyQt6.QtWidgets import QApplication def qapp(app: QApplication) -> None: # 待测试函数 app.quit() END $ cat <<'END' > tests/test_main.py # 测试文件 import pytest from PyQt6.QtWidgets import QApplication import myproject.main from typing import Any QtBot = Any # 缺失类型提示 def test_app(qtbot: QtBot) -> None: app = QApplication([]) myproject.main.qapp(app) assert 1 == 1 END $ poetry install $ poetry shell $ pytest
错误日志
============================================================================ test session starts ============================================================================ platform linux -- Python 3.10.4, pytest-7.4.0, pluggy-1.2.0 PyQt6 6.5.1 -- Qt runtime 6.5.1 -- Qt compiled 6.5.1 rootdir: /home/hakon/test/python/pytest-qt/qtbot/myproject plugins: qt-4.2.0 collected 1 item tests/test_main.py Fatal Python error: Segmentation fault Current thread 0x00007f24e2fc1740 (most recent call first): File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/_pytest/python.py", line 194 in pytest_pyfunc_call File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/pluggy/_callers.py", line 80 in _multicall File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/pluggy/_manager.py", line 112 in _hookexec File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/pluggy/_hooks.py", line 433 in __call__ File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/_pytest/python.py", line 1788 in runtest File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/_pytest/runner.py", line 169 in pytest_runtest_call File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/pluggy/_callers.py", line 80 in _multicall File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/pluggy/_manager.py", line 112 in _hookexec File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/pluggy/_hooks.py", line 433 in __call__ File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/_pytest/runner.py", line 262 in <lambda> File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/_pytest/runner.py", line 341 in from_call File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/_pytest/runner.py", line 261 in call_runtest_hook File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/_pytest/runner.py", line 222 in call_and_report File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/_pytest/runner.py", line 133 in runtestprotocol File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/_pytest/runner.py", line 114 in pytest_runtest_protocol File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/pluggy/_callers.py", line 80 in _multicall File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/pluggy/_manager.py", line 112 in _hookexec File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/pluggy/_hooks.py", line 433 in __call__ File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/_pytest/main.py", line 349 in pytest_runtestloop File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/pluggy/_callers.py", line 80 in _multicall File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/pluggy/_manager.py", line 112 in _hookexec File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/pluggy/_hooks.py", line 433 in __call__ File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/_pytest/main.py", line 324 in _main File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/_pytest/main.py", line 270 in wrap_session File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/_pytest/main.py", line 317 in pytest_cmdline_main File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/pluggy/_callers.py", line 80 in _multicall File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/pluggy/_manager.py", line 112 in _hookexec File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/pluggy/_hooks.py", line 433 in __call__ File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/_pytest/config/__init__.py", line 166 in main File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/lib/python3.10/site-packages/_pytest/config/__init__.py", line 189 in console_main File "/home/hakon/.cache/pypoetry/virtualenvs/myproject-rfHFWcwh-py3.10/bin/pytest", line 8 in <module> Extension modules: PyQt6.QtCore, PyQt6.QtGui, PyQt6.QtWidgets, PyQt6.QtTest (total: 4) Segmentation fault (core dumped)
解决方案
问题根源
qtbot fixture内部会自动创建一个QApplication实例,而你在测试代码中又手动创建了另一个实例。Qt规定一个进程只能存在一个QApplication实例,重复创建会导致底层资源冲突,最终触发段错误。
修复代码
修改tests/test_main.py,使用qtbot已创建的QApplication实例,不要手动初始化:
import pytest import myproject.main from pytestqt.qtbot import QtBot # 导入正确的类型提示 def test_app(qtbot: QtBot) -> None: # 直接使用qtbot自带的app实例 myproject.main.qapp(qtbot.app) assert 1 == 1
或者通过QApplication.instance()获取已存在的实例:
import pytest from PyQt6.QtWidgets import QApplication import myproject.main from pytestqt.qtbot import QtBot def test_app(qtbot: QtBot) -> None: app = QApplication.instance() myproject.main.qapp(app) assert 1 == 1
额外提示
- pytest-qt会自动管理QApplication的生命周期,测试开始前创建,测试结束后销毁,无需手动处理。
- 导入
from pytestqt.qtbot import QtBot代替Any,能获得正确的类型提示,提升开发体验。
内容的提问来源于stack exchange,提问作者Håkon Hægland
相关产品推荐
相关产品推荐

